Skip to content

Commit 366e92c

Browse files
eric-feng-2011Eric Feng
and
Eric Feng
authored
Interval (#116)
* add date_add, interval sql still running into issues * Add Interval SQL support * uncomment out the other tests * resolve comments * change interval equality Co-authored-by: Eric Feng <[email protected]>
1 parent 6e0d1c9 commit 366e92c

File tree

4 files changed

+186
-1
lines changed

4 files changed

+186
-1
lines changed

src/enclave/Enclave/ExpressionEvaluation.h

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,25 @@ class FlatbuffersExpressionEvaluator {
265265

266266
case tuix::ExprUnion_Literal:
267267
{
268+
auto * literal = static_cast<const tuix::Literal *>(expr->expr());
269+
const tuix::Field *value = literal->value();
270+
271+
// If type is CalendarInterval, manually return a calendar interval field.
272+
// Otherwise 'days' disappears in conversion.
273+
if (value->value_type() == tuix::FieldUnion_CalendarIntervalField) {
274+
275+
auto *interval = value->value_as_CalendarIntervalField();
276+
uint32_t months = interval->months();
277+
uint32_t days = interval->days();
278+
uint64_t ms = interval->microseconds();
279+
280+
return tuix::CreateField(
281+
builder,
282+
tuix::FieldUnion_CalendarIntervalField,
283+
tuix::CreateCalendarIntervalField(builder, months, days, ms).Union(),
284+
false);
285+
}
286+
268287
return flatbuffers_copy<tuix::Field>(
269288
static_cast<const tuix::Literal *>(expr->expr())->value(), builder);
270289
}
@@ -403,6 +422,7 @@ class FlatbuffersExpressionEvaluator {
403422
auto add = static_cast<const tuix::Add *>(expr->expr());
404423
auto left_offset = eval_helper(row, add->left());
405424
auto right_offset = eval_helper(row, add->right());
425+
406426
return eval_binary_arithmetic_op<tuix::Add, std::plus>(
407427
builder,
408428
flatbuffers::GetTemporaryPointer(builder, left_offset),
@@ -1041,6 +1061,102 @@ class FlatbuffersExpressionEvaluator {
10411061
false);
10421062
}
10431063

1064+
// Time expressions
1065+
case tuix::ExprUnion_DateAdd:
1066+
{
1067+
auto c = static_cast<const tuix::DateAdd *>(expr->expr());
1068+
auto left_offset = eval_helper(row, c->left());
1069+
auto right_offset = eval_helper(row, c->right());
1070+
1071+
// Note: These temporary pointers will be invalidated when we next write to builder
1072+
const tuix::Field *left = flatbuffers::GetTemporaryPointer(builder, left_offset);
1073+
const tuix::Field *right = flatbuffers::GetTemporaryPointer(builder, right_offset);
1074+
1075+
if (left->value_type() != tuix::FieldUnion_DateField
1076+
|| right->value_type() != tuix::FieldUnion_IntegerField) {
1077+
throw std::runtime_error(
1078+
std::string("tuix::DateAdd requires date Date, increment Integer, not ")
1079+
+ std::string("date ")
1080+
+ std::string(tuix::EnumNameFieldUnion(left->value_type()))
1081+
+ std::string(", increment ")
1082+
+ std::string(tuix::EnumNameFieldUnion(right->value_type())));
1083+
}
1084+
1085+
bool result_is_null = left->is_null() || right->is_null();
1086+
1087+
if (!result_is_null) {
1088+
auto left_field = static_cast<const tuix::DateField *>(left->value());
1089+
auto right_field = static_cast<const tuix::IntegerField *>(right->value());
1090+
1091+
uint32_t result = left_field->value() + right_field->value();
1092+
1093+
return tuix::CreateField(
1094+
builder,
1095+
tuix::FieldUnion_DateField,
1096+
tuix::CreateDateField(builder, result).Union(),
1097+
result_is_null);
1098+
} else {
1099+
uint32_t result = 0;
1100+
return tuix::CreateField(
1101+
builder,
1102+
tuix::FieldUnion_DateField,
1103+
tuix::CreateDateField(builder, result).Union(),
1104+
result_is_null);
1105+
}
1106+
}
1107+
1108+
case tuix::ExprUnion_DateAddInterval:
1109+
{
1110+
auto c = static_cast<const tuix::DateAddInterval *>(expr->expr());
1111+
auto left_offset = eval_helper(row, c->left());
1112+
auto right_offset = eval_helper(row, c->right());
1113+
1114+
// Note: These temporary pointers will be invalidated when we next write to builder
1115+
const tuix::Field *left = flatbuffers::GetTemporaryPointer(builder, left_offset);
1116+
const tuix::Field *right = flatbuffers::GetTemporaryPointer(builder, right_offset);
1117+
1118+
if (left->value_type() != tuix::FieldUnion_DateField
1119+
|| right->value_type() != tuix::FieldUnion_CalendarIntervalField) {
1120+
throw std::runtime_error(
1121+
std::string("tuix::DateAddInterval requires date Date, interval CalendarIntervalField, not ")
1122+
+ std::string("date ")
1123+
+ std::string(tuix::EnumNameFieldUnion(left->value_type()))
1124+
+ std::string(", interval ")
1125+
+ std::string(tuix::EnumNameFieldUnion(right->value_type())));
1126+
}
1127+
1128+
bool result_is_null = left->is_null() || right->is_null();
1129+
uint32_t result = 0;
1130+
1131+
if (!result_is_null) {
1132+
1133+
auto left_field = static_cast<const tuix::DateField *>(left->value());
1134+
auto right_field = static_cast<const tuix::CalendarIntervalField *>(right->value());
1135+
1136+
//This is an approximation
1137+
//TODO take into account leap seconds
1138+
uint64_t date = 86400L*left_field->value();
1139+
struct tm tm;
1140+
secs_to_tm(date, &tm);
1141+
tm.tm_mon += right_field->months();
1142+
tm.tm_mday += right_field->days();
1143+
time_t time = std::mktime(&tm);
1144+
uint32_t result = (time + (right_field->microseconds() / 1000)) / 86400L;
1145+
1146+
return tuix::CreateField(
1147+
builder,
1148+
tuix::FieldUnion_DateField,
1149+
tuix::CreateDateField(builder, result).Union(),
1150+
result_is_null);
1151+
} else {
1152+
return tuix::CreateField(
1153+
builder,
1154+
tuix::FieldUnion_DateField,
1155+
tuix::CreateDateField(builder, result).Union(),
1156+
result_is_null);
1157+
}
1158+
}
1159+
10441160
case tuix::ExprUnion_Year:
10451161
{
10461162
auto e = static_cast<const tuix::Year *>(expr->expr());

src/flatbuffers/Expr.fbs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,9 @@ union ExprUnion {
3636
Exp,
3737
ClosestPoint,
3838
CreateArray,
39-
Upper
39+
Upper,
40+
DateAdd,
41+
DateAddInterval
4042
}
4143

4244
table Expr {
@@ -165,6 +167,16 @@ table Year {
165167
child:Expr;
166168
}
167169

170+
table DateAdd {
171+
left:Expr;
172+
right:Expr;
173+
}
174+
175+
table DateAddInterval {
176+
left:Expr;
177+
right:Expr;
178+
}
179+
168180
// Math expressions
169181
table Exp {
170182
child:Expr;

src/main/scala/edu/berkeley/cs/rise/opaque/Utils.scala

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ import org.apache.spark.sql.catalyst.expressions.Attribute
4444
import org.apache.spark.sql.catalyst.expressions.AttributeReference
4545
import org.apache.spark.sql.catalyst.expressions.Cast
4646
import org.apache.spark.sql.catalyst.expressions.Contains
47+
import org.apache.spark.sql.catalyst.expressions.DateAdd
48+
import org.apache.spark.sql.catalyst.expressions.DateAddInterval
4749
import org.apache.spark.sql.catalyst.expressions.Descending
4850
import org.apache.spark.sql.catalyst.expressions.Divide
4951
import org.apache.spark.sql.catalyst.expressions.EndsWith
@@ -69,6 +71,7 @@ import org.apache.spark.sql.catalyst.expressions.SortOrder
6971
import org.apache.spark.sql.catalyst.expressions.StartsWith
7072
import org.apache.spark.sql.catalyst.expressions.Substring
7173
import org.apache.spark.sql.catalyst.expressions.Subtract
74+
import org.apache.spark.sql.catalyst.expressions.TimeAdd
7275
import org.apache.spark.sql.catalyst.expressions.UnaryMinus
7376
import org.apache.spark.sql.catalyst.expressions.Upper
7477
import org.apache.spark.sql.catalyst.expressions.Year
@@ -1000,13 +1003,28 @@ object Utils extends Logging {
10001003
tuix.Contains.createContains(
10011004
builder, leftOffset, rightOffset))
10021005

1006+
// Time expressions
10031007
case (Year(child), Seq(childOffset)) =>
10041008
tuix.Expr.createExpr(
10051009
builder,
10061010
tuix.ExprUnion.Year,
10071011
tuix.Year.createYear(
10081012
builder, childOffset))
10091013

1014+
case (DateAdd(left, right), Seq(leftOffset, rightOffset)) =>
1015+
tuix.Expr.createExpr(
1016+
builder,
1017+
tuix.ExprUnion.DateAdd,
1018+
tuix.DateAdd.createDateAdd(
1019+
builder, leftOffset, rightOffset))
1020+
1021+
case (DateAddInterval(left, right, _, _), Seq(leftOffset, rightOffset)) =>
1022+
tuix.Expr.createExpr(
1023+
builder,
1024+
tuix.ExprUnion.DateAddInterval,
1025+
tuix.DateAddInterval.createDateAddInterval(
1026+
builder, leftOffset, rightOffset))
1027+
10101028
// Math expressions
10111029
case (Exp(child), Seq(childOffset)) =>
10121030
tuix.Expr.createExpr(

src/test/scala/edu/berkeley/cs/rise/opaque/OpaqueOperatorTests.scala

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,45 @@ trait OpaqueOperatorTests extends FunSuite with BeforeAndAfterAll { self =>
122122
}
123123
}
124124

125+
testAgainstSpark("Interval SQL") { securityLevel =>
126+
val data = Seq(Tuple2(1, new java.sql.Date(new java.util.Date().getTime())))
127+
val df = makeDF(data, securityLevel, "index", "time")
128+
df.createTempView("Interval")
129+
try {
130+
spark.sql("SELECT time + INTERVAL 7 DAY FROM Interval").collect
131+
} finally {
132+
spark.catalog.dropTempView("Interval")
133+
}
134+
}
135+
136+
testAgainstSpark("Interval Week SQL") { securityLevel =>
137+
val data = Seq(Tuple2(1, new java.sql.Date(new java.util.Date().getTime())))
138+
val df = makeDF(data, securityLevel, "index", "time")
139+
df.createTempView("Interval")
140+
try {
141+
spark.sql("SELECT time + INTERVAL 7 WEEK FROM Interval").collect
142+
} finally {
143+
spark.catalog.dropTempView("Interval")
144+
}
145+
}
146+
147+
testAgainstSpark("Interval Month SQL") { securityLevel =>
148+
val data = Seq(Tuple2(1, new java.sql.Date(new java.util.Date().getTime())))
149+
val df = makeDF(data, securityLevel, "index", "time")
150+
df.createTempView("Interval")
151+
try {
152+
spark.sql("SELECT time + INTERVAL 6 MONTH FROM Interval").collect
153+
} finally {
154+
spark.catalog.dropTempView("Interval")
155+
}
156+
}
157+
158+
testAgainstSpark("Date Add") { securityLevel =>
159+
val data = Seq(Tuple2(1, new java.sql.Date(new java.util.Date().getTime())))
160+
val df = makeDF(data, securityLevel, "index", "time")
161+
df.select(date_add($"time", 3)).collect
162+
}
163+
125164
testAgainstSpark("create DataFrame from sequence") { securityLevel =>
126165
val data = for (i <- 0 until 5) yield ("foo", i)
127166
makeDF(data, securityLevel, "word", "count").collect

0 commit comments

Comments
 (0)