embulk-filter-row 0.2.2 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (28) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +3 -0
  3. data/CHANGELOG.md +6 -0
  4. data/README.md +124 -4
  5. data/build.gradle +15 -4
  6. data/classpath/embulk-filter-row-0.3.0.jar +0 -0
  7. data/example/and.yml +0 -7
  8. data/example/example.yml +0 -7
  9. data/example/where.yml +28 -0
  10. data/script/byaccj.sh +29 -0
  11. data/src/main/java/org/embulk/filter/row/{AbstractColumnVisitor.java → AbstractGuardColumnVisitor.java} +9 -17
  12. data/src/main/java/org/embulk/filter/row/BuildColumnVisitorImpl.java +98 -0
  13. data/src/main/java/org/embulk/filter/row/{ColumnVisitorAndImpl.java → GuardColumnVisitorAndImpl.java} +11 -45
  14. data/src/main/java/org/embulk/filter/row/{ColumnVisitorOrImpl.java → GuardColumnVisitorOrImpl.java} +11 -45
  15. data/src/main/java/org/embulk/filter/row/GuardColumnVisitorWhereImpl.java +28 -0
  16. data/src/main/java/org/embulk/filter/row/RowFilterPlugin.java +49 -16
  17. data/src/main/java/org/embulk/filter/row/where/Parser.java +831 -0
  18. data/src/main/java/org/embulk/filter/row/where/ParserExp.java +290 -0
  19. data/src/main/java/org/embulk/filter/row/where/ParserLiteral.java +277 -0
  20. data/src/main/java/org/embulk/filter/row/where/ParserNode.java +6 -0
  21. data/src/main/java/org/embulk/filter/row/where/ParserVal.java +78 -0
  22. data/src/main/java/org/embulk/filter/row/where/Yylex.java +833 -0
  23. data/src/main/java/org/embulk/filter/row/where/_lexer.l +108 -0
  24. data/src/main/java/org/embulk/filter/row/where/_parser.y +137 -0
  25. data/src/test/java/org/embulk/filter/row/where/TestParser.java +383 -0
  26. data/src/test/java/org/embulk/filter/row/where/TestYylex.java +256 -0
  27. metadata +19 -5
  28. data/classpath/embulk-filter-row-0.2.2.jar +0 -0
@@ -0,0 +1,108 @@
1
+ package org.embulk.filter.row.where;
2
+
3
+ import org.embulk.spi.Schema;
4
+ %%
5
+
6
+ %byaccj
7
+
8
+ %{
9
+ private StringBuffer string = new StringBuffer();
10
+
11
+ protected Parser yyparser;
12
+ protected Schema schema;
13
+
14
+ public Yylex(String str, Parser yyparser) {
15
+ this(new java.io.StringReader(str));
16
+ this.yyparser = yyparser;
17
+ this.schema = yyparser.schema;
18
+ }
19
+ %}
20
+
21
+ %state STRING
22
+ %state IDENTIFIER
23
+
24
+ Number = -?[0-9]+(\.[0-9]+)?
25
+ QuotedIdentifierChar = [^\r\n\"\\]
26
+ NonQuotedIdentifier = [a-zA-Z$][a-zA-z0-9\.\-_]*
27
+ StringChar = [^\r\n\'\\]+
28
+ Newline = \n|\r|\r\n
29
+
30
+ %%
31
+
32
+ <YYINITIAL> {
33
+ /* operators */
34
+ "(" { return (int) yycharat(0); }
35
+ ")" { return (int) yycharat(0); }
36
+ "AND" { return Parser.AND; }
37
+ "OR" { return Parser.OR; }
38
+ "=" { return Parser.EQ; }
39
+ "<>" | "!=" { return Parser.NEQ; }
40
+ "!=" { return Parser.NEQ; }
41
+ ">" { return Parser.GT; }
42
+ ">=" { return Parser.GE; }
43
+ "<" { return Parser.LT; }
44
+ "<=" { return Parser.LE; }
45
+ "START_WITH" { return Parser.START_WITH; }
46
+ "END_WITH" { return Parser.END_WITH; }
47
+ "INCLUDE" { return Parser.INCLUDE; }
48
+ "IS" { return Parser.IS; }
49
+ "NOT" { return Parser.NOT; }
50
+ "NULL" { return Parser.NULL; }
51
+ "TIMESTAMP" { return Parser.TIMESTAMP; }
52
+
53
+ /* boolean literal */
54
+ "true" | "TRUE" { yyparser.yylval = new ParserVal(new BooleanLiteral(true)); return Parser.BOOLEAN; }
55
+ "false" | "FALSE" { yyparser.yylval = new ParserVal(new BooleanLiteral(false)); return Parser.BOOLEAN; }
56
+
57
+ /* number literal */
58
+ {Number} { yyparser.yylval = new ParserVal(new NumberLiteral(yytext())); return Parser.NUMBER; }
59
+
60
+ /* identifier literal */
61
+ {NonQuotedIdentifier} { yyparser.yylval = new ParserVal(new IdentifierLiteral(yytext(), schema)); return Parser.IDENTIFIER; }
62
+ \" { yybegin(IDENTIFIER); string.setLength(0); }
63
+
64
+ /* string literal */
65
+ \' { yybegin(STRING); string.setLength(0); }
66
+
67
+ /* whitespace */
68
+ [ \t]+ { }
69
+
70
+ /* newline */
71
+ {Newline} { }
72
+ }
73
+
74
+ <IDENTIFIER> {
75
+ \" { yybegin(YYINITIAL); yyparser.yylval = new ParserVal(new IdentifierLiteral(string.toString(), schema)); return Parser.IDENTIFIER; }
76
+
77
+ {QuotedIdentifierChar}+ { string.append( yytext() ); }
78
+
79
+ /* escape sequences */
80
+ "\\\"" { string.append( '\"' ); }
81
+ "\\'" { string.append( '\'' ); }
82
+ "\\\\" { string.append( '\\' ); }
83
+
84
+ /* error cases */
85
+ \\. { throw new RuntimeException("yylex: Illegal escape sequence \""+yytext()+"\""); }
86
+ }
87
+
88
+ <STRING> {
89
+ \' { yybegin(YYINITIAL); yyparser.yylval = new ParserVal(new StringLiteral(string.toString())); return Parser.STRING; }
90
+
91
+ {StringChar}+ { string.append( yytext() ); }
92
+
93
+ /* escape sequences */
94
+ "\\b" { string.append( '\b' ); }
95
+ "\\t" { string.append( '\t' ); }
96
+ "\\n" { string.append( '\n' ); }
97
+ "\\f" { string.append( '\f' ); }
98
+ "\\r" { string.append( '\r' ); }
99
+ "\\\"" { string.append( '\"' ); }
100
+ "\\'" { string.append( '\'' ); }
101
+ "\\\\" { string.append( '\\' ); }
102
+
103
+ /* error cases */
104
+ \\. { throw new RuntimeException("yylex: Illegal escape sequence \""+yytext()+"\""); }
105
+ }
106
+
107
+ /* error fallback */
108
+ [^] { throw new RuntimeException("yylex: Unexpected character '"+yytext()+"'"); }
@@ -0,0 +1,137 @@
1
+ %{
2
+ import org.embulk.spi.Column;
3
+ import org.embulk.spi.Schema;
4
+ %}
5
+
6
+ /* YACC Declarations */
7
+ %token EQ /* = */
8
+ %token NEQ /* <> != */
9
+ %token GT /* > */
10
+ %token GE /* >= */
11
+ %token LT /* < */
12
+ %token LE /* <= */
13
+
14
+ %token START_WITH
15
+ %token END_WITH
16
+ %token INCLUDE
17
+ %token IS
18
+ %token NOT
19
+
20
+ %token AND
21
+ %token OR
22
+
23
+ %token NULL
24
+ %token BOOLEAN
25
+ %token STRING
26
+ %token NUMBER
27
+ %token IDENTIFIER
28
+
29
+ %token TIMESTAMP
30
+
31
+ %left OR
32
+ %left AND
33
+ %right TIMESTAMP
34
+ %right NOT
35
+
36
+ /* Grammar follows */
37
+ %%
38
+ input: /* empty string */
39
+ | exp { root = $1; }
40
+ ;
41
+
42
+ timestamp: TIMESTAMP STRING { $$ = new ParserVal(new TimestampLiteral($2)); }
43
+ | TIMESTAMP NUMBER { $$ = new ParserVal(new TimestampLiteral($2)); }
44
+
45
+ exp: IDENTIFIER EQ BOOLEAN { $$ = new ParserVal(new BooleanOpExp($1, $3, EQ)); }
46
+ | IDENTIFIER NEQ BOOLEAN { $$ = new ParserVal(new BooleanOpExp($1, $3, NEQ)); }
47
+ | BOOLEAN EQ IDENTIFIER { $$ = new ParserVal(new BooleanOpExp($1, $3, EQ)); }
48
+ | BOOLEAN NEQ IDENTIFIER { $$ = new ParserVal(new BooleanOpExp($1, $3, NEQ)); }
49
+ | IDENTIFIER EQ NUMBER { $$ = new ParserVal(new NumberOpExp($1, $3, EQ)); }
50
+ | IDENTIFIER NEQ NUMBER { $$ = new ParserVal(new NumberOpExp($1, $3, NEQ)); }
51
+ | IDENTIFIER GT NUMBER { $$ = new ParserVal(new NumberOpExp($1, $3, GT)); }
52
+ | IDENTIFIER GE NUMBER { $$ = new ParserVal(new NumberOpExp($1, $3, GE)); }
53
+ | IDENTIFIER LT NUMBER { $$ = new ParserVal(new NumberOpExp($1, $3, LT)); }
54
+ | IDENTIFIER LE NUMBER { $$ = new ParserVal(new NumberOpExp($1, $3, LE)); }
55
+ | NUMBER EQ IDENTIFIER { $$ = new ParserVal(new NumberOpExp($1, $3, EQ)); }
56
+ | NUMBER NEQ IDENTIFIER { $$ = new ParserVal(new NumberOpExp($1, $3, NEQ)); }
57
+ | NUMBER GT IDENTIFIER { $$ = new ParserVal(new NumberOpExp($1, $3, GT)); }
58
+ | NUMBER GE IDENTIFIER { $$ = new ParserVal(new NumberOpExp($1, $3, GE)); }
59
+ | NUMBER LT IDENTIFIER { $$ = new ParserVal(new NumberOpExp($1, $3, LT)); }
60
+ | NUMBER LE IDENTIFIER { $$ = new ParserVal(new NumberOpExp($1, $3, LE)); }
61
+ | IDENTIFIER EQ STRING { $$ = new ParserVal(new StringOpExp($1, $3, EQ)); }
62
+ | IDENTIFIER NEQ STRING { $$ = new ParserVal(new StringOpExp($1, $3, NEQ)); }
63
+ | IDENTIFIER START_WITH STRING { $$ = new ParserVal(new StringOpExp($1, $3, START_WITH)); }
64
+ | IDENTIFIER END_WITH STRING { $$ = new ParserVal(new StringOpExp($1, $3, END_WITH)); }
65
+ | IDENTIFIER INCLUDE STRING { $$ = new ParserVal(new StringOpExp($1, $3, INCLUDE)); }
66
+ | STRING EQ IDENTIFIER { $$ = new ParserVal(new StringOpExp($1, $3, EQ)); }
67
+ | STRING NEQ IDENTIFIER { $$ = new ParserVal(new StringOpExp($1, $3, NEQ)); }
68
+ | STRING START_WITH IDENTIFIER { $$ = new ParserVal(new StringOpExp($1, $3, START_WITH)); }
69
+ | STRING END_WITH IDENTIFIER { $$ = new ParserVal(new StringOpExp($1, $3, END_WITH)); }
70
+ | STRING INCLUDE IDENTIFIER { $$ = new ParserVal(new StringOpExp($1, $3, INCLUDE)); }
71
+ | IDENTIFIER EQ timestamp { $$ = new ParserVal(new TimestampOpExp($1, $3, EQ)); }
72
+ | IDENTIFIER NEQ timestamp { $$ = new ParserVal(new TimestampOpExp($1, $3, NEQ)); }
73
+ | IDENTIFIER GT timestamp { $$ = new ParserVal(new TimestampOpExp($1, $3, GT)); }
74
+ | IDENTIFIER GE timestamp { $$ = new ParserVal(new TimestampOpExp($1, $3, GE)); }
75
+ | IDENTIFIER LT timestamp { $$ = new ParserVal(new TimestampOpExp($1, $3, LT)); }
76
+ | IDENTIFIER LE timestamp { $$ = new ParserVal(new TimestampOpExp($1, $3, LE)); }
77
+ | timestamp EQ IDENTIFIER { $$ = new ParserVal(new TimestampOpExp($1, $3, EQ)); }
78
+ | timestamp NEQ IDENTIFIER { $$ = new ParserVal(new TimestampOpExp($1, $3, NEQ)); }
79
+ | timestamp GT IDENTIFIER { $$ = new ParserVal(new TimestampOpExp($1, $3, GT)); }
80
+ | timestamp GE IDENTIFIER { $$ = new ParserVal(new TimestampOpExp($1, $3, GE)); }
81
+ | timestamp LT IDENTIFIER { $$ = new ParserVal(new TimestampOpExp($1, $3, LT)); }
82
+ | timestamp LE IDENTIFIER { $$ = new ParserVal(new TimestampOpExp($1, $3, LE)); }
83
+ | IDENTIFIER IS NULL { $$ = new ParserVal(new NullOpExp($1, EQ)); }
84
+ | IDENTIFIER IS NOT NULL { $$ = new ParserVal(new NullOpExp($1, NEQ)); }
85
+ | exp OR exp { $$ = new ParserVal(new LogicalOpExp($1, $3, OR)); }
86
+ | exp AND exp { $$ = new ParserVal(new LogicalOpExp($1, $3, AND)); }
87
+ | NOT exp { $$ = new ParserVal(new NegateOpExp($2)); }
88
+ | '(' exp ')' { $$ = $2; }
89
+ ;
90
+ %%
91
+
92
+ protected Schema schema;
93
+ protected Yylex lexer;
94
+ protected ParserVal root;
95
+
96
+ public Parser(final Schema schema)
97
+ {
98
+ this.schema = schema;
99
+ }
100
+
101
+ public Parser(final Schema schema, boolean yydebug)
102
+ {
103
+ this.schema = schema;
104
+ this.yydebug = yydebug;
105
+ }
106
+
107
+ public ParserExp parse(String str)
108
+ {
109
+ lexer = new Yylex(str, this);
110
+ yyparse();
111
+ return ((ParserExp)(root.obj));
112
+ }
113
+
114
+ private int yylex () {
115
+ int token = -1;
116
+ try {
117
+ token = lexer.yylex(); // next token
118
+ }
119
+ catch (java.io.IOException e) {
120
+ e.printStackTrace(); // should not happen
121
+ }
122
+ return token;
123
+ }
124
+
125
+ void yyerror(String s)
126
+ {
127
+ throw new RuntimeException("yyerror: " + s);
128
+ }
129
+
130
+ /*public static void main(String args[])
131
+ {
132
+ Parser yyparser = new Parser();
133
+ ParserExp exp = yyparser.parse("boolean = true");
134
+ HashMap<String, Object> variables = new HashMap<>();
135
+ variables.put("boolean", Boolean.TRUE);
136
+ System.out.println("ans: " + exp.eval(variables));
137
+ }*/
@@ -0,0 +1,383 @@
1
+ package org.embulk.filter.row.where;
2
+
3
+ import org.embulk.EmbulkTestRuntime;
4
+ import org.embulk.config.ConfigException;
5
+ import org.embulk.spi.Page;
6
+ import org.embulk.spi.PageReader;
7
+ import org.embulk.spi.PageTestUtils;
8
+ import org.embulk.spi.Schema;
9
+ import org.embulk.spi.SchemaConfigException;
10
+ import org.embulk.spi.time.Timestamp;
11
+
12
+ import org.embulk.spi.time.TimestampParseException;
13
+ import org.jruby.embed.ScriptingContainer;
14
+ import org.junit.BeforeClass;
15
+ import org.junit.Rule;
16
+ import org.junit.Test;
17
+ import org.msgpack.value.Value;
18
+ import org.msgpack.value.ValueFactory;
19
+
20
+ import java.util.List;
21
+
22
+ import static org.embulk.spi.type.Types.BOOLEAN;
23
+ import static org.embulk.spi.type.Types.DOUBLE;
24
+ import static org.embulk.spi.type.Types.JSON;
25
+ import static org.embulk.spi.type.Types.LONG;
26
+ import static org.embulk.spi.type.Types.STRING;
27
+ import static org.embulk.spi.type.Types.TIMESTAMP;
28
+ import static org.junit.Assert.assertFalse;
29
+ import static org.junit.Assert.assertTrue;
30
+
31
+ public class TestParser
32
+ {
33
+ private static EmbulkTestRuntime runtime = new EmbulkTestRuntime(); // very slow
34
+ private static ScriptingContainer jruby = new ScriptingContainer();
35
+
36
+ private static PageReader buildPageReader(Schema schema, final Object... objects)
37
+ {
38
+ PageReader pageReader = new PageReader(schema);
39
+ List<Page> pages = PageTestUtils.buildPage(runtime.getBufferAllocator(), schema, objects);
40
+ for (Page page : pages) {
41
+ pageReader.setPage(page);
42
+ }
43
+ pageReader.nextRecord();
44
+ return pageReader;
45
+ }
46
+
47
+ private static PageReader reader;
48
+ private static Schema schema;
49
+
50
+ @BeforeClass
51
+ public static void setupBeforeClass()
52
+ {
53
+ ParserLiteral.setJRuby(jruby);
54
+
55
+ // {"k1":{"k1":"v"},"k2":{"k2":"v"}}
56
+ Value k1 = ValueFactory.newString("k1");
57
+ Value k2 = ValueFactory.newString("k2");
58
+ Value v = ValueFactory.newString("v");
59
+ Value map = ValueFactory.newMap(
60
+ k1, ValueFactory.newMap(k1, v),
61
+ k2, ValueFactory.newMap(k2, v));
62
+
63
+ schema = Schema.builder()
64
+ .add("timestamp", TIMESTAMP)
65
+ .add("string", STRING)
66
+ .add("boolean", BOOLEAN)
67
+ .add("long", LONG)
68
+ .add("double", DOUBLE)
69
+ .add("true", BOOLEAN)
70
+ .add("null", BOOLEAN)
71
+ .add("json", JSON)
72
+ .build();
73
+
74
+ reader = buildPageReader(schema,
75
+ Timestamp.ofEpochSecond(1, 500000000),
76
+ "string",
77
+ true,
78
+ 1L,
79
+ 1.5,
80
+ true,
81
+ null,
82
+ map
83
+ );
84
+ }
85
+
86
+ @Test
87
+ public void testIdentifierLiteral()
88
+ {
89
+ Parser parser = new Parser(schema);
90
+ ParserExp exp;
91
+
92
+ exp = parser.parse("boolean = true");
93
+ assertTrue(exp.eval(reader));
94
+
95
+ exp = parser.parse("\"true\" = true");
96
+ assertTrue(exp.eval(reader));
97
+
98
+ try {
99
+ exp = parser.parse("\"unknown\" IS NULL");
100
+ assertTrue(false);
101
+ }
102
+ catch (SchemaConfigException e) {
103
+ }
104
+ }
105
+
106
+ @Test
107
+ public void testBooleanOpExp()
108
+ {
109
+ Parser parser = new Parser(schema);
110
+ ParserExp exp;
111
+
112
+ exp = parser.parse("boolean = true");
113
+ assertTrue(exp.eval(reader));
114
+ exp = parser.parse("boolean = false");
115
+ assertFalse(exp.eval(reader));
116
+
117
+ exp = parser.parse("boolean != false");
118
+ assertTrue(exp.eval(reader));
119
+ exp = parser.parse("boolean != true");
120
+ assertFalse(exp.eval(reader));
121
+
122
+ exp = parser.parse("true = boolean");
123
+ assertTrue(exp.eval(reader));
124
+
125
+ try {
126
+ exp = parser.parse("timestamp = true");
127
+ assertTrue(false);
128
+ }
129
+ catch (ConfigException e) {
130
+ }
131
+ }
132
+
133
+ @Test
134
+ public void testNumberOpExp()
135
+ {
136
+ Parser parser = new Parser(schema);
137
+ ParserExp exp;
138
+
139
+ exp = parser.parse("double = 1.5");
140
+ assertTrue(exp.eval(reader));
141
+ exp = parser.parse("double = 1.0");
142
+ assertFalse(exp.eval(reader));
143
+
144
+ exp = parser.parse("double != 1.0");
145
+ assertTrue(exp.eval(reader));
146
+ exp = parser.parse("double != 1.5");
147
+ assertFalse(exp.eval(reader));
148
+
149
+ exp = parser.parse("double > 1.0");
150
+ assertTrue(exp.eval(reader));
151
+ exp = parser.parse("double > 1.5");
152
+ assertFalse(exp.eval(reader));
153
+
154
+ exp = parser.parse("double >= 1.5");
155
+ assertTrue(exp.eval(reader));
156
+ exp = parser.parse("double >= 2.0");
157
+ assertFalse(exp.eval(reader));
158
+
159
+ exp = parser.parse("double < 2.0");
160
+ assertTrue(exp.eval(reader));
161
+ exp = parser.parse("double < 1.5");
162
+ assertFalse(exp.eval(reader));
163
+
164
+ exp = parser.parse("double <= 1.5");
165
+ assertTrue(exp.eval(reader));
166
+ exp = parser.parse("double <= 1.0");
167
+ assertFalse(exp.eval(reader));
168
+
169
+ exp = parser.parse("1.5 = double");
170
+ assertTrue(exp.eval(reader));
171
+
172
+ try {
173
+ exp = parser.parse("timestamp = 1.5");
174
+ assertTrue(false);
175
+ }
176
+ catch (ConfigException e) {
177
+ }
178
+ }
179
+
180
+ @Test
181
+ public void testStringOpExp()
182
+ {
183
+ Parser parser = new Parser(schema);
184
+ ParserExp exp;
185
+
186
+ exp = parser.parse("string = 'string'");
187
+ assertTrue(exp.eval(reader));
188
+ exp = parser.parse("string = 'foobar'");
189
+ assertFalse(exp.eval(reader));
190
+
191
+ exp = parser.parse("string != 'foobar'");
192
+ assertTrue(exp.eval(reader));
193
+ exp = parser.parse("string != 'string'");
194
+ assertFalse(exp.eval(reader));
195
+
196
+ exp = parser.parse("string <> 'foobar'");
197
+ assertTrue(exp.eval(reader));
198
+ exp = parser.parse("string <> 'string'");
199
+ assertFalse(exp.eval(reader));
200
+
201
+ exp = parser.parse("string START_WITH 's'");
202
+ assertTrue(exp.eval(reader));
203
+ exp = parser.parse("string START_WITH 'f'");
204
+ assertFalse(exp.eval(reader));
205
+
206
+ exp = parser.parse("string END_WITH 'g'");
207
+ assertTrue(exp.eval(reader));
208
+ exp = parser.parse("string END_WITH 'r'");
209
+ assertFalse(exp.eval(reader));
210
+
211
+ exp = parser.parse("string INCLUDE 'tr'");
212
+ assertTrue(exp.eval(reader));
213
+ exp = parser.parse("string INCLUDE 'oo'");
214
+ assertFalse(exp.eval(reader));
215
+
216
+ exp = parser.parse("'string' = string");
217
+ assertTrue(exp.eval(reader));
218
+
219
+ try {
220
+ exp = parser.parse("timestamp = 'string'");
221
+ assertTrue(false);
222
+ }
223
+ catch (ConfigException e) {
224
+ }
225
+ }
226
+
227
+ @Test
228
+ public void testTimestampOpExpWithNumber()
229
+ {
230
+ Parser parser = new Parser(schema);
231
+ ParserExp exp;
232
+
233
+ exp = parser.parse("timestamp = TIMESTAMP 1.5");
234
+ assertTrue(exp.eval(reader));
235
+ exp = parser.parse("timestamp = TIMESTAMP 1.0");
236
+ assertFalse(exp.eval(reader));
237
+
238
+ exp = parser.parse("timestamp != TIMESTAMP 1.0");
239
+ assertTrue(exp.eval(reader));
240
+ exp = parser.parse("timestamp != TIMESTAMP 1.5");
241
+ assertFalse(exp.eval(reader));
242
+
243
+ exp = parser.parse("timestamp > TIMESTAMP 1.0");
244
+ assertTrue(exp.eval(reader));
245
+ exp = parser.parse("timestamp > TIMESTAMP 1.5");
246
+ assertFalse(exp.eval(reader));
247
+
248
+ exp = parser.parse("timestamp >= TIMESTAMP 1.5");
249
+ assertTrue(exp.eval(reader));
250
+ exp = parser.parse("timestamp >= TIMESTAMP 2.0");
251
+ assertFalse(exp.eval(reader));
252
+
253
+ exp = parser.parse("timestamp < TIMESTAMP 2.0");
254
+ assertTrue(exp.eval(reader));
255
+ exp = parser.parse("timestamp < TIMESTAMP 1.5");
256
+ assertFalse(exp.eval(reader));
257
+
258
+ exp = parser.parse("timestamp <= TIMESTAMP 1.5");
259
+ assertTrue(exp.eval(reader));
260
+ exp = parser.parse("timestamp <= TIMESTAMP 1.0");
261
+ assertFalse(exp.eval(reader));
262
+
263
+ exp = parser.parse("TIMESTAMP 1.5 = timestamp");
264
+ assertTrue(exp.eval(reader));
265
+ }
266
+
267
+ @Test
268
+ public void testTimestampOpExpWithString()
269
+ {
270
+ Parser parser = new Parser(schema);
271
+ ParserExp exp;
272
+
273
+ exp = parser.parse("timestamp = TIMESTAMP '1970-01-01 09:00:01.5 +0900'");
274
+ assertTrue(exp.eval(reader));
275
+ exp = parser.parse("timestamp = TIMESTAMP '1970-01-01 09:00:01.0 +09:00'");
276
+ assertFalse(exp.eval(reader));
277
+
278
+ exp = parser.parse("timestamp != TIMESTAMP '1970-01-01 09:00:01.0 +0900'");
279
+ assertTrue(exp.eval(reader));
280
+ exp = parser.parse("timestamp != TIMESTAMP '1970-01-01 09:00:01.5 +0900'");
281
+ assertFalse(exp.eval(reader));
282
+
283
+ exp = parser.parse("timestamp > TIMESTAMP '1970-01-01 09:00:01.0 +0900'");
284
+ assertTrue(exp.eval(reader));
285
+ exp = parser.parse("timestamp > TIMESTAMP '1970-01-01 09:00:01.5 +0900'");
286
+ assertFalse(exp.eval(reader));
287
+
288
+ exp = parser.parse("timestamp >= TIMESTAMP '1970-01-01 09:00:01.5 +09:00'");
289
+ assertTrue(exp.eval(reader));
290
+ exp = parser.parse("timestamp >= TIMESTAMP '1970-01-01 09:00:02.0 +09:00'");
291
+ assertFalse(exp.eval(reader));
292
+
293
+ exp = parser.parse("timestamp < TIMESTAMP '1970-01-01 09:00:02.0 +09:00'");
294
+ assertTrue(exp.eval(reader));
295
+ exp = parser.parse("timestamp < TIMESTAMP '1970-01-01 09:00:01.5 +09:00'");
296
+ assertFalse(exp.eval(reader));
297
+
298
+ exp = parser.parse("timestamp <= TIMESTAMP '1970-01-01 09:00:01.5 +09:00'");
299
+ assertTrue(exp.eval(reader));
300
+ exp = parser.parse("timestamp <= TIMESTAMP '1970-01-01 09:00:01.0 +09:00'");
301
+ assertFalse(exp.eval(reader));
302
+
303
+ exp = parser.parse("TIMESTAMP '1970-01-01 09:00:01.5 +09:00' = timestamp");
304
+ assertTrue(exp.eval(reader));
305
+
306
+ exp = parser.parse("timestamp = TIMESTAMP '1970-01-01 09:00:01.5 +0900'");
307
+ assertTrue(exp.eval(reader));
308
+ exp = parser.parse("timestamp = TIMESTAMP '1970-01-01 00:00:01.5'");
309
+ assertTrue(exp.eval(reader));
310
+ exp = parser.parse("timestamp = TIMESTAMP '1970-01-01 09:00:01 +09:00'");
311
+ assertFalse(exp.eval(reader));
312
+ exp = parser.parse("timestamp = TIMESTAMP '1970-01-01 00:00:01'");
313
+ assertFalse(exp.eval(reader));
314
+ exp = parser.parse("timestamp = TIMESTAMP '1970-01-01 +09:00'");
315
+ assertFalse(exp.eval(reader));
316
+ exp = parser.parse("timestamp = TIMESTAMP '1970-01-01'");
317
+ assertFalse(exp.eval(reader));
318
+
319
+ try {
320
+ parser.parse("timestamp = TIMESTAMP '1970:01:01'");
321
+ assertTrue(false);
322
+ }
323
+ catch (TimestampParseException ex) {
324
+ }
325
+ }
326
+
327
+ @Test
328
+ public void testNullOpExp()
329
+ {
330
+ Parser parser = new Parser(schema);
331
+ ParserExp exp;
332
+
333
+ exp = parser.parse("null IS NULL");
334
+ assertTrue(exp.eval(reader));
335
+ exp = parser.parse("null IS NOT NULL");
336
+ assertFalse(exp.eval(reader));
337
+
338
+ exp = parser.parse("string IS NOT NULL");
339
+ assertTrue(exp.eval(reader));
340
+ exp = parser.parse("string IS NULL");
341
+ assertFalse(exp.eval(reader));
342
+ }
343
+
344
+ @Test
345
+ public void testLogicalOpExp()
346
+ {
347
+ Parser parser = new Parser(schema);
348
+ ParserExp exp;
349
+
350
+ exp = parser.parse("\"true\" = true AND \"true\" = true");
351
+ assertTrue(exp.eval(reader));
352
+ exp = parser.parse("\"true\" = true AND \"true\" = false");
353
+ assertFalse(exp.eval(reader));
354
+
355
+ exp = parser.parse("\"true\" = false OR \"true\" = true");
356
+ assertTrue(exp.eval(reader));
357
+ exp = parser.parse("\"true\" = false OR \"true\" = false");
358
+ assertFalse(exp.eval(reader));
359
+
360
+ // a AND b OR c #=> (a AND b) OR c
361
+ // a OR b AND c #=> a OR (b AND c)
362
+ exp = parser.parse("\"true\" = true OR \"true\" = false AND \"true\" = false");
363
+ assertTrue(exp.eval(reader));
364
+ exp = parser.parse("( \"true\" = true OR \"true\" = false ) AND \"true\" = false");
365
+ assertFalse(exp.eval(reader));
366
+ }
367
+
368
+ @Test
369
+ public void testNegateOpExp()
370
+ {
371
+ Parser parser = new Parser(schema);
372
+ ParserExp exp;
373
+
374
+ exp = parser.parse("NOT \"true\" = false");
375
+ assertTrue(exp.eval(reader));
376
+ exp = parser.parse("NOT ( \"true\" = false )");
377
+ assertTrue(exp.eval(reader));
378
+
379
+ // NOT a AND B #=> (NOT a) AND B
380
+ exp = parser.parse("NOT \"true\" = false AND \"true\" = true");
381
+ assertTrue(exp.eval(reader));
382
+ }
383
+ }