From 22f6a3082d5e9698e3be4208ca68cd6724239fd0 Mon Sep 17 00:00:00 2001 From: Martin Date: Sat, 23 Nov 2019 16:18:49 +0100 Subject: Interpreter conversions (#26) --- .../mimuw/cloudatlas/interpreter/Interpreter.java | 9 +- .../mimuw/cloudatlas/interpreter/ResultColumn.java | 16 +- .../edu/mimuw/cloudatlas/model/ValueDuration.java | 8 +- .../cloudatlas/interpreter/InterpreterTests.java | 484 ++++++++++++++++++++- 4 files changed, 501 insertions(+), 16 deletions(-) diff --git a/src/main/java/pl/edu/mimuw/cloudatlas/interpreter/Interpreter.java b/src/main/java/pl/edu/mimuw/cloudatlas/interpreter/Interpreter.java index 289f99d..6129f48 100644 --- a/src/main/java/pl/edu/mimuw/cloudatlas/interpreter/Interpreter.java +++ b/src/main/java/pl/edu/mimuw/cloudatlas/interpreter/Interpreter.java @@ -329,8 +329,13 @@ public class Interpreter { } public Result visit(CondExprAndC expr, Environment env) { - // TODO - throw new UnsupportedOperationException("CondExprAndC Not yet implemented"); + try { + Result left = expr.condexpr_1.accept(new CondExprInterpreter(), env); + Result right = expr.condexpr_2.accept(new CondExprInterpreter(), env); + return left.and(right); + } catch(Exception exception) { + throw new InsideQueryException(PrettyPrinter.print(expr), exception); + } } public Result visit(CondExprNotC expr, Environment env) { diff --git a/src/main/java/pl/edu/mimuw/cloudatlas/interpreter/ResultColumn.java b/src/main/java/pl/edu/mimuw/cloudatlas/interpreter/ResultColumn.java index b551955..1c0db30 100644 --- a/src/main/java/pl/edu/mimuw/cloudatlas/interpreter/ResultColumn.java +++ b/src/main/java/pl/edu/mimuw/cloudatlas/interpreter/ResultColumn.java @@ -4,6 +4,7 @@ import java.util.ArrayList; import java.util.List; import pl.edu.mimuw.cloudatlas.model.Type; +import pl.edu.mimuw.cloudatlas.model.TypePrimitive; import pl.edu.mimuw.cloudatlas.model.TypeCollection; import pl.edu.mimuw.cloudatlas.model.Value; import pl.edu.mimuw.cloudatlas.model.ValueBoolean; @@ -100,7 +101,7 @@ class ResultColumn extends Result { @Override public Result random(int size) { - return new ResultColumn( + return new ResultSingle( randomList( new ValueList( column, @@ -124,13 +125,18 @@ class ResultColumn extends Result { @Override public ResultSingle isNull() { - throw new UnsupportedOperationException("Operation isNull not supported yet."); - // return new ResultSingle(new ValueBoolean(value.isNull())); + return new ResultSingle(new ValueBoolean(true)); } @Override public Type getType() { - throw new UnsupportedOperationException("Operation getType not supported yet."); - // return value.getType(); + Type type = TypePrimitive.NULL; + for (Value value : column) { + if (value.getType() != TypePrimitive.NULL) { + type = value.getType(); + } + } + + return type; } } diff --git a/src/main/java/pl/edu/mimuw/cloudatlas/model/ValueDuration.java b/src/main/java/pl/edu/mimuw/cloudatlas/model/ValueDuration.java index 7a74776..ad14a30 100644 --- a/src/main/java/pl/edu/mimuw/cloudatlas/model/ValueDuration.java +++ b/src/main/java/pl/edu/mimuw/cloudatlas/model/ValueDuration.java @@ -264,9 +264,9 @@ public class ValueDuration extends ValueSimple { remainingUnits /= 24; long days = remainingUnits; - return (positive ? "+" : "-") + Long.toString(days) + " " + Long.toString(hours) - + ":" + Long.toString(minutes) + ":" + Long.toString(seconds) + "." + - Long.toString(milliseconds); + return (positive ? "+" : "-") + String.format("%d %02d:%02d:%02d.%03d", + days, hours, minutes, seconds, milliseconds + ); } @Override @@ -274,6 +274,8 @@ public class ValueDuration extends ValueSimple { switch(type.getPrimaryType()) { case STRING: return getValue() == null? ValueString.NULL_STRING : new ValueString(makeString()); + case INT: + return new ValueInt(getValue() == null? null : getValue()); case DURATION: return this; default: diff --git a/src/test/java/pl/edu/mimuw/cloudatlas/interpreter/InterpreterTests.java b/src/test/java/pl/edu/mimuw/cloudatlas/interpreter/InterpreterTests.java index 3d8584d..aaac9ce 100644 --- a/src/test/java/pl/edu/mimuw/cloudatlas/interpreter/InterpreterTests.java +++ b/src/test/java/pl/edu/mimuw/cloudatlas/interpreter/InterpreterTests.java @@ -7,12 +7,14 @@ import java.io.File; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.net.URL; +import java.util.Calendar; import static org.junit.Assert.*; import org.junit.Test; import org.junit.Ignore; import pl.edu.mimuw.cloudatlas.model.AttributesMap; +import pl.edu.mimuw.cloudatlas.model.ValueBoolean; import pl.edu.mimuw.cloudatlas.model.ValueTime; import pl.edu.mimuw.cloudatlas.model.ZMI; @@ -34,6 +36,467 @@ public class InterpreterTests { } } + @Test + public void testAvg() throws Exception { + assertInterpreterRun( + "SELECT avg(cpu_usage) AS cpu_usage", + new String[] { + "/uw: cpu_usage: 0.5", + "/pjwstk: cpu_usage: 0.25", + "/: cpu_usage: 0.375", + } + ); + } + + @Test + public void testCount() throws Exception { + assertInterpreterRun( + "SELECT count(cpu_usage) AS cpu_usage", + new String[] { + "/uw: cpu_usage: 2", + "/pjwstk: cpu_usage: 2", + "/: cpu_usage: 2", + } + ); + } + + @Test + public void testSum() throws Exception { + assertInterpreterRun( + "SELECT sum(cpu_usage) AS cpu_usage", + new String[] { + "/uw: cpu_usage: 1.0", + "/pjwstk: cpu_usage: 0.5", + "/: cpu_usage: 1.5", + } + ); + } + + @Test + public void testFirst() throws Exception { + assertInterpreterRun( + "SELECT first(1, unfold(php_modules)) AS php_modules", + new String[] { + "/pjwstk: php_modules: [rewrite]", + "/: php_modules: [rewrite]", + } + ); + } + + @Test + public void testLast() throws Exception { + assertInterpreterRun( + "SELECT last(1, unfold(php_modules)) AS php_modules", + new String[] { + "/pjwstk: php_modules: [odbc]", + "/: php_modules: [odbc]", + } + ); + } + + @Test + public void testRandom() throws Exception { + String query = "SELECT random(1, unfold(php_modules)) AS php_modules"; + ByteArrayInputStream in = new ByteArrayInputStream(query.getBytes()); + String output = runInterpreter(in); + String expected1 = join(new String[] { + "/pjwstk: php_modules: [odbc]", + "/: php_modules: [odbc]", + }); + String expected2 = join(new String[] { + "/pjwstk: php_modules: [rewrite]", + "/: php_modules: [rewrite]", + }); + + assertTrue(output.equals(expected1) || output.equals(expected2)); + } + + @Test + public void testMin() throws Exception { + assertInterpreterRun( + "SELECT min(cpu_usage) AS cpu_usage", + new String[] { + "/uw: cpu_usage: 0.1", + "/pjwstk: cpu_usage: 0.1", + "/: cpu_usage: 0.1", + } + ); + } + + @Test + public void testMax() throws Exception { + assertInterpreterRun( + "SELECT max(cpu_usage) AS cpu_usage", + new String[] { + "/uw: cpu_usage: 0.9", + "/pjwstk: cpu_usage: 0.4", + "/: cpu_usage: 0.9", + } + ); + } + + @Test + public void testLand() throws Exception { + assertInterpreterRun( + "SELECT max(cpu_usage) AS cpu_usage; SELECT land(cpu_usage < 0.5) AS low_cpu", + new String[] { + "/uw: cpu_usage: 0.9", + "/uw: low_cpu: false", + "/pjwstk: cpu_usage: 0.4", + "/pjwstk: low_cpu: true", + "/: cpu_usage: 0.9", + "/: low_cpu: false", + } + ); + } + + @Test + public void testLor() throws Exception { + assertInterpreterRun( + "SELECT max(cpu_usage) AS cpu_usage; SELECT lor(cpu_usage > 0.5) AS high_cpu", + new String[] { + "/uw: cpu_usage: 0.9", + "/uw: high_cpu: true", + "/pjwstk: cpu_usage: 0.4", + "/pjwstk: high_cpu: false", + "/: cpu_usage: 0.9", + "/: high_cpu: true", + } + ); + } + + @Test + public void testNow() throws Exception { + ValueTime timeBefore = new ValueTime(Calendar.getInstance().getTimeInMillis()); + String query = "SELECT now() AS now"; + ByteArrayInputStream in = new ByteArrayInputStream(query.getBytes()); + String output = runInterpreter(in); + ValueTime timeAfter = new ValueTime(Calendar.getInstance().getTimeInMillis()); + String[] lines = output.split("\n"); + assertEquals(3, lines.length); + for (String line : lines) { + String timestamp = line.split(":", 3)[2]; + ValueTime resultTime = new ValueTime(timestamp); + assertFalse(((ValueBoolean) resultTime.isLowerThan(timeBefore)).getValue()); + assertFalse(((ValueBoolean) timeAfter.isLowerThan(resultTime)).getValue()); + } + } + + @Test + public void testEpoch() throws Exception { + assertInterpreterRun( + "SELECT epoch() AS epoch", + new String[] { + "/uw: epoch: 2000/01/01 00:00:00.000", + "/pjwstk: epoch: 2000/01/01 00:00:00.000", + "/: epoch: 2000/01/01 00:00:00.000", + } + ); + } + + @Test + public void testSize() throws Exception { + assertInterpreterRun( + "SELECT max(size(name)) AS max_len_name", + new String[] { + "/uw: max_len_name: 8", + "/pjwstk: max_len_name: 10", + "/: max_len_name: 6", + } + ); + } + + @Test + public void testRound() throws Exception { + assertInterpreterRun( + "SELECT max(cpu_usage) AS cpu_usage; SELECT round(max(cpu_usage)) AS approximate_cpu", + new String[] { + "/uw: cpu_usage: 0.9", + "/uw: approximate_cpu: 1.0", + "/pjwstk: cpu_usage: 0.4", + "/pjwstk: approximate_cpu: 0.0", + "/: cpu_usage: 0.9", + "/: approximate_cpu: 1.0", + } + ); + } + + @Test + public void testFloor() throws Exception { + assertInterpreterRun( + "SELECT max(cpu_usage) AS cpu_usage; SELECT floor(0.2 + max(cpu_usage)) AS approximate_cpu", + new String[] { + "/uw: cpu_usage: 0.9", + "/uw: approximate_cpu: 1.0", + "/pjwstk: cpu_usage: 0.4", + "/pjwstk: approximate_cpu: 0.0", + "/: cpu_usage: 0.9", + "/: approximate_cpu: 1.0", + } + ); + } + + @Test + public void testCeil() throws Exception { + assertInterpreterRun( + "SELECT max(cpu_usage) AS cpu_usage; SELECT ceil(0.2 + max(cpu_usage)) AS approximate_cpu", + new String[] { + "/uw: cpu_usage: 0.9", + "/uw: approximate_cpu: 2.0", + "/pjwstk: cpu_usage: 0.4", + "/pjwstk: approximate_cpu: 1.0", + "/: cpu_usage: 0.9", + "/: approximate_cpu: 2.0", + } + ); + } + + @Test + public void testBoolToString() throws Exception { + assertInterpreterRun( + "SELECT to_string(true) + \"x\" AS truex", + new String[] { + "/uw: truex: truex", + "/pjwstk: truex: truex", + "/: truex: truex", + } + ); + } + + @Test + public void testStringToBool() throws Exception { + assertInterpreterRun( + "SELECT to_boolean(\"true\") AND true AS tru", + new String[] { + "/uw: tru: true", + "/pjwstk: tru: true", + "/: tru: true", + } + ); + } + + @Test + public void testIntToString() throws Exception { + assertInterpreterRun( + "SELECT to_string(1) + \"x\" AS onex", + new String[] { + "/uw: onex: 1x", + "/pjwstk: onex: 1x", + "/: onex: 1x", + } + ); + } + + @Test + public void testStringToInt() throws Exception { + assertInterpreterRun( + "SELECT to_integer(\"1\") + 1 AS two", + new String[] { + "/uw: two: 2", + "/pjwstk: two: 2", + "/: two: 2", + } + ); + } + + @Test + public void testDoublePlusIntFails() throws Exception { + assertInterpreterRun( + "SELECT 1 + 1.0 AS two", + new String[] { + } + ); + } + + @Test + public void testDoubleToInt() throws Exception { + assertInterpreterRun( + "SELECT 1 + to_integer(1.0) AS two", + new String[] { + "/uw: two: 2", + "/pjwstk: two: 2", + "/: two: 2", + } + ); + } + + @Test + public void testIntToDouble() throws Exception { + assertInterpreterRun( + "SELECT to_double(1) + 1.0 AS two", + new String[] { + "/uw: two: 2.0", + "/pjwstk: two: 2.0", + "/: two: 2.0", + } + ); + } + + @Test + public void testIntToDuration() throws Exception { + assertInterpreterRun( + "SELECT to_duration(1) AS one_ms", + new String[] { + "/uw: one_ms: +0 00:00:00.001", + "/pjwstk: one_ms: +0 00:00:00.001", + "/: one_ms: +0 00:00:00.001", + } + ); + } + + @Test + public void testDurationToInt() throws Exception { + assertInterpreterRun( + "SELECT to_integer(to_duration(1)) AS one", + new String[] { + "/uw: one: 1", + "/pjwstk: one: 1", + "/: one: 1", + } + ); + } + + @Test + public void testDoubleToString() throws Exception { + assertInterpreterRun( + "SELECT to_string(1.0) + \"x\" AS onex", + new String[] { + "/uw: onex: 1.0x", + "/pjwstk: onex: 1.0x", + "/: onex: 1.0x", + } + ); + } + + @Test + public void testStringToDouble() throws Exception { + assertInterpreterRun( + "SELECT to_double(\"1.0\") + 1.0 AS two", + new String[] { + "/uw: two: 2.0", + "/pjwstk: two: 2.0", + "/: two: 2.0", + } + ); + } + + @Test + public void testSetToList() throws Exception { + assertInterpreterRun( + "SELECT first(5, unfold(to_list(php_modules) + to_list(php_modules))) AS php_modules", + new String[] { + "/pjwstk: php_modules: [rewrite, rewrite, odbc, odbc]", + "/: php_modules: [rewrite, rewrite, odbc, odbc, rewrite]" + } + ); + } + + @Test + public void testListToSet() throws Exception { + assertInterpreterRun( + "SELECT to_set(first(5, unfold(to_list(php_modules) + to_list(php_modules)))) AS php_modules", + new String[] { + "/pjwstk: php_modules: {odbc, rewrite}", + "/: php_modules: {odbc, rewrite}" + } + ); + } + + @Test + public void testTimeToString() throws Exception { + assertInterpreterRun( + "SELECT max(to_string(timestamp)) + \"x\" AS timex", + new String[] { + "/uw: timex: 2012/11/09 21:03:00.000x", + "/pjwstk: timex: 2012/11/09 21:13:00.000x", + "/: timex: 2012/11/09 20:08:13.123x" + } + ); + } + + @Test + public void testStringToTime() throws Exception { + assertInterpreterRun( + "SELECT to_time(\"2012/11/09 21:03:00.000\") + to_duration(1) AS time", + new String[] { + "/uw: time: 2012/11/09 21:03:00.001", + "/pjwstk: time: 2012/11/09 21:03:00.001", + "/: time: 2012/11/09 21:03:00.001" + } + ); + } + + @Test + public void testDurationToString() throws Exception { + assertInterpreterRun( + "SELECT to_string(epoch() - epoch()) + \"x\" AS zerox", + new String[] { + "/uw: zerox: +0 00:00:00.000x", + "/pjwstk: zerox: +0 00:00:00.000x", + "/: zerox: +0 00:00:00.000x" + } + ); + } + + @Test + public void testStringToDuration() throws Exception { + assertInterpreterRun( + "SELECT to_duration(\"+0 00:01:12.000\") + to_duration(1) AS dur", + new String[] { + "/uw: dur: +0 00:01:12.001", + "/pjwstk: dur: +0 00:01:12.001", + "/: dur: +0 00:01:12.001" + } + ); + } + + @Test + public void testContactToString() throws Exception { + assertInterpreterRun( + "SELECT first(1, to_string(unfold(members))) AS member", + new String[] { + "/uw: member: [(/uw/violet07, /10.1.1.10)]", + "/pjwstk: member: [(/uw/whatever01, /82.111.52.56)]", + } + ); + } + + @Test + public void testListToString() throws Exception { + assertInterpreterRun( + "SELECT first(1, to_string(to_list(php_modules)) + \"x\") AS listx", + new String[] { + "/pjwstk: listx: [[rewrite]x]" + } + ); + } + + @Test + public void testSetToString() throws Exception { + assertInterpreterRun( + "SELECT first(1, to_string(to_set(php_modules)) + \"x\") AS setx", + new String[] { + "/pjwstk: setx: [{rewrite}x]" + } + ); + } + + private void assertInterpreterRun(String query, String[] expectedOutput) throws Exception { + ByteArrayInputStream in = new ByteArrayInputStream(query.getBytes()); + + String expected = join(expectedOutput); + + runTest(in, expected); + } + + private String join(String[] strings) { + if (strings.length == 0) { + return ""; + } + + return String.join("\n", strings) + "\n"; + } + @Test public void fileTest01() throws Exception { runFileTest(1); @@ -135,19 +598,28 @@ public class InterpreterTests { URL testOut = InterpreterTests.class.getResource(i + ".out"); FileInputStream in = new FileInputStream(test.getFile()); + + File expectedFile = new File(testOut.getFile()); + FileInputStream expectedIn = new FileInputStream(expectedFile); + byte[] buffer = new byte[(int)expectedFile.length()]; + expectedIn.read(buffer); + String expected = new String(buffer, "UTF-8"); + + runTest(in, expected); + } + + private String runInterpreter(InputStream in) throws Exception { ByteArrayOutputStream outByteArray = new ByteArrayOutputStream(); PrintStream outPrint = new PrintStream(outByteArray); ZMI root = Main.createTestHierarchy(); Main.runTest(in, outPrint, root); - String actual = outByteArray.toString(); + return outByteArray.toString(); + } - File expectedFile = new File(testOut.getFile()); - FileInputStream expectedIn = new FileInputStream(expectedFile); - byte[] buffer = new byte[(int)expectedFile.length()]; - expectedIn.read(buffer); - String expected = new String(buffer, "UTF-8"); + private void runTest(InputStream in, String expected) throws Exception { + String actual = runInterpreter(in); assertEquals(expected, actual); } -- cgit v1.2.3