fix issue 29
git-svn-id: https://asterixdb.googlecode.com/svn/branches/asterix_stabilization_printerfix@919 eaa15691-b419-025a-1212-ee371bd00084
diff --git a/asterix-algebra/src/main/java/edu/uci/ics/asterix/optimizer/rules/IntroduceStaticTypeCastRule.java b/asterix-algebra/src/main/java/edu/uci/ics/asterix/optimizer/rules/IntroduceStaticTypeCastRule.java
index c8a8f26..a3edd9a 100644
--- a/asterix-algebra/src/main/java/edu/uci/ics/asterix/optimizer/rules/IntroduceStaticTypeCastRule.java
+++ b/asterix-algebra/src/main/java/edu/uci/ics/asterix/optimizer/rules/IntroduceStaticTypeCastRule.java
@@ -92,43 +92,59 @@
return false;
context.addToDontApplySet(this, opRef.getValue());
AbstractLogicalOperator op1 = (AbstractLogicalOperator) opRef.getValue();
- if (op1.getOperatorTag() != LogicalOperatorTag.SINK)
- return false;
- AbstractLogicalOperator op2 = (AbstractLogicalOperator) op1.getInputs().get(0).getValue();
- if (op2.getOperatorTag() != LogicalOperatorTag.INSERT_DELETE)
- return false;
- AbstractLogicalOperator op3 = (AbstractLogicalOperator) op2.getInputs().get(0).getValue();
- if (op3.getOperatorTag() != LogicalOperatorTag.ASSIGN)
- return false;
-
- /**
- * get required record type
- */
- InsertDeleteOperator insertDeleteOperator = (InsertDeleteOperator) op2;
- AssignOperator topAssignOperator = (AssignOperator) op3;
- AqlDataSource dataSource = (AqlDataSource) insertDeleteOperator.getDataSource();
- IAType[] schemaTypes = (IAType[]) dataSource.getSchemaTypes();
- ARecordType requiredRecordType = (ARecordType) schemaTypes[schemaTypes.length - 1];
-
- /**
- * get input record type to the insert operator
- */
- List<LogicalVariable> usedVariables = new ArrayList<LogicalVariable>();
- VariableUtilities.getUsedVariables(topAssignOperator, usedVariables);
-
- // the used variable should contain the record that will be inserted
- // but it will not fail in many cases even if the used variable set is
- // empty
- if (usedVariables.size() == 0)
- return false;
- LogicalVariable oldRecordVariable = usedVariables.get(0);
- LogicalVariable inputRecordVar = usedVariables.get(0);
- IVariableTypeEnvironment env = topAssignOperator.computeOutputTypeEnvironment(context);
- ARecordType inputRecordType = (ARecordType) env.getVarType(inputRecordVar);
-
- AbstractLogicalOperator currentOperator = topAssignOperator;
+ AbstractLogicalOperator assignOp = null;
+ IAType requiredRecordType = null;
+ IAType inputRecordType = null;
+ boolean isTopWrite = false;
List<LogicalVariable> producedVariables = new ArrayList<LogicalVariable>();
+ LogicalVariable oldRecordVariable;
+ if (op1.getOperatorTag() == LogicalOperatorTag.SINK) {
+ AbstractLogicalOperator op2 = (AbstractLogicalOperator) op1.getInputs().get(0).getValue();
+ if (op2.getOperatorTag() != LogicalOperatorTag.INSERT_DELETE)
+ return false;
+ assignOp = (AbstractLogicalOperator) op2.getInputs().get(0).getValue();
+ if (assignOp.getOperatorTag() != LogicalOperatorTag.ASSIGN)
+ return false;
+ /**
+ * get required record type
+ */
+ InsertDeleteOperator insertDeleteOperator = (InsertDeleteOperator) op2;
+ AqlDataSource dataSource = (AqlDataSource) insertDeleteOperator.getDataSource();
+ IAType[] schemaTypes = (IAType[]) dataSource.getSchemaTypes();
+ requiredRecordType = schemaTypes[schemaTypes.length - 1];
+
+ AssignOperator topAssignOperator = (AssignOperator) assignOp;
+ List<LogicalVariable> usedVariables = new ArrayList<LogicalVariable>();
+ VariableUtilities.getUsedVariables(topAssignOperator, usedVariables);
+
+ // the used variable should contain the record that will be inserted
+ // but it will not fail in many cases even if the used variable set is
+ // empty
+ if (usedVariables.size() == 0)
+ return false;
+ oldRecordVariable = usedVariables.get(0);
+ LogicalVariable inputRecordVar = usedVariables.get(0);
+ IVariableTypeEnvironment env = topAssignOperator.computeOutputTypeEnvironment(context);
+ inputRecordType = (IAType) env.getVarType(inputRecordVar);
+ } else if (op1.getOperatorTag() == LogicalOperatorTag.WRITE) {
+ AbstractLogicalOperator op2 = (AbstractLogicalOperator) op1.getInputs().get(0).getValue();
+ if (op2.getOperatorTag() != LogicalOperatorTag.PROJECT)
+ return false;
+ assignOp = (AbstractLogicalOperator) op2.getInputs().get(0).getValue();
+ if (assignOp.getOperatorTag() != LogicalOperatorTag.ASSIGN)
+ return false;
+ isTopWrite = true;
+ VariableUtilities.getProducedVariables(assignOp, producedVariables);
+ oldRecordVariable = producedVariables.get(0);
+ LogicalVariable inputVar = producedVariables.get(0);
+ IVariableTypeEnvironment env = assignOp.computeOutputTypeEnvironment(context);
+ inputRecordType = (IAType) env.getVarType(inputVar);
+ } else {
+ return false;
+ }
+
+ AbstractLogicalOperator currentOperator = assignOp;
/**
* find the assign operator for the "input record" to the insert_delete
* operator
@@ -151,9 +167,17 @@
ScalarFunctionCallExpression funcExpr = (ScalarFunctionCallExpression) expr;
// that expression has been rewritten, and it will not
// fail but just return false
- if (TypeComputerUtilities.getRequiredType(funcExpr) != null)
+ if (TypeComputerUtilities.getRequiredType(funcExpr) != null) {
return false;
- IVariableTypeEnvironment assignEnv = topAssignOperator.computeOutputTypeEnvironment(context);
+ }
+ if (isTopWrite) {
+ if (funcExpr.getFunctionIdentifier() != AsterixBuiltinFunctions.UNORDERED_LIST_CONSTRUCTOR
+ && funcExpr.getFunctionIdentifier() != AsterixBuiltinFunctions.ORDERED_LIST_CONSTRUCTOR) {
+ return false;
+ }
+ requiredRecordType = inputRecordType;
+ }
+ IVariableTypeEnvironment assignEnv = assignOp.computeOutputTypeEnvironment(context);
rewriteFuncExpr(funcExpr, requiredRecordType, inputRecordType, assignEnv);
}
context.computeAndSetTypeEnvironmentForOperator(originalAssign);
diff --git a/asterix-algebra/src/main/java/edu/uci/ics/asterix/optimizer/rules/SetClosedRecordConstructorsRule.java b/asterix-algebra/src/main/java/edu/uci/ics/asterix/optimizer/rules/SetClosedRecordConstructorsRule.java
index c121ff6..ad70d6f 100644
--- a/asterix-algebra/src/main/java/edu/uci/ics/asterix/optimizer/rules/SetClosedRecordConstructorsRule.java
+++ b/asterix-algebra/src/main/java/edu/uci/ics/asterix/optimizer/rules/SetClosedRecordConstructorsRule.java
@@ -92,47 +92,55 @@
boolean changed = false;
if (expr.getFunctionIdentifier().equals(AsterixBuiltinFunctions.OPEN_RECORD_CONSTRUCTOR)) {
ARecordType reqType = (ARecordType) TypeComputerUtilities.getRequiredType(expr);
- if (reqType != null) {
- if (reqType.isOpen())
- allClosed = false;
- }
- int n = expr.getArguments().size();
- if (n % 2 > 0) {
- throw new AlgebricksException("Record constructor expected to have an even number of arguments: "
- + expr);
- }
- for (int i = 0; i < n / 2; i++) {
- ILogicalExpression a0 = expr.getArguments().get(2 * i).getValue();
- if (a0.getExpressionTag() != LogicalExpressionTag.CONSTANT) {
- allClosed = false;
+ if (reqType == null || !reqType.isOpen()) {
+ int n = expr.getArguments().size();
+ if (n % 2 > 0) {
+ throw new AlgebricksException(
+ "Record constructor expected to have an even number of arguments: " + expr);
}
- Mutable<ILogicalExpression> aRef1 = expr.getArguments().get(2 * i + 1);
- ILogicalExpression a1 = aRef1.getValue();
- ClosedDataInfo cdi = a1.accept(this, arg);
- if (!cdi.dataIsClosed) {
- allClosed = false;
+ for (int i = 0; i < n / 2; i++) {
+ ILogicalExpression a0 = expr.getArguments().get(2 * i).getValue();
+ if (a0.getExpressionTag() != LogicalExpressionTag.CONSTANT) {
+ allClosed = false;
+ }
+ Mutable<ILogicalExpression> aRef1 = expr.getArguments().get(2 * i + 1);
+ ILogicalExpression a1 = aRef1.getValue();
+ ClosedDataInfo cdi = a1.accept(this, arg);
+ if (!cdi.dataIsClosed) {
+ allClosed = false;
+ }
+ if (cdi.expressionChanged) {
+ aRef1.setValue(cdi.expression);
+ changed = true;
+ }
}
- if (cdi.expressionChanged) {
- aRef1.setValue(cdi.expression);
+ if (allClosed) {
+ expr.setFunctionInfo(FunctionUtils
+ .getFunctionInfo(AsterixBuiltinFunctions.CLOSED_RECORD_CONSTRUCTOR));
+ GlobalConfig.ASTERIX_LOGGER.finest("Switching to CLOSED record constructor in " + expr + ".\n");
changed = true;
}
}
- if (allClosed) {
- expr.setFunctionInfo(FunctionUtils
- .getFunctionInfo(AsterixBuiltinFunctions.CLOSED_RECORD_CONSTRUCTOR));
- GlobalConfig.ASTERIX_LOGGER.finest("Switching to CLOSED record constructor in " + expr + ".\n");
- changed = true;
- }
} else {
- for (Mutable<ILogicalExpression> e : expr.getArguments()) {
- ILogicalExpression ale = e.getValue();
- ClosedDataInfo cdi = ale.accept(this, arg);
- if (!cdi.dataIsClosed) {
- allClosed = false;
+ boolean rewrite = true;
+ if (expr.getFunctionIdentifier().equals(AsterixBuiltinFunctions.ORDERED_LIST_CONSTRUCTOR)
+ || (expr.getFunctionIdentifier().equals(AsterixBuiltinFunctions.UNORDERED_LIST_CONSTRUCTOR))) {
+ IAType reqType = TypeComputerUtilities.getRequiredType(expr);
+ if (reqType == null) {
+ rewrite = false;
}
- if (cdi.expressionChanged) {
- e.setValue(cdi.expression);
- changed = true;
+ }
+ if (rewrite) {
+ for (Mutable<ILogicalExpression> e : expr.getArguments()) {
+ ILogicalExpression ale = e.getValue();
+ ClosedDataInfo cdi = ale.accept(this, arg);
+ if (!cdi.dataIsClosed) {
+ allClosed = false;
+ }
+ if (cdi.expressionChanged) {
+ e.setValue(cdi.expression);
+ changed = true;
+ }
}
}
}
@@ -144,7 +152,8 @@
throws AlgebricksException {
Object varType = env.getVarType(expr.getVariableReference());
if (varType == null) {
- throw new AlgebricksException("Could not infer type for variable '" + expr.getVariableReference() + "'.");
+ throw new AlgebricksException("Could not infer type for variable '" + expr.getVariableReference()
+ + "'.");
}
boolean dataIsClosed = isClosedRec((IAType) varType);
return new ClosedDataInfo(false, dataIsClosed, expr);
diff --git a/asterix-app/src/test/resources/runtimets/queries/open-closed/query-issue29.aql b/asterix-app/src/test/resources/runtimets/queries/open-closed/query-issue29.aql
new file mode 100644
index 0000000..240330f
--- /dev/null
+++ b/asterix-app/src/test/resources/runtimets/queries/open-closed/query-issue29.aql
@@ -0,0 +1,63 @@
+write output to nc1:"rttest/open-closed_query-issue29.adm";
+
+let $tweets :=
+{{
+ {
+ "tweetid": "1023",
+ "user": {
+ "screen-name": "dflynn24",
+ "lang": "en",
+ "friends_count": 46,
+ "statuses_count": 987,
+ "name": "danielle flynn",
+ "followers_count": 47
+ },
+ "sender-location": "40.904177,-72.958996",
+ "send-time": "2010-02-21T11:56:02-05:00",
+ "referred-topics": {{ "verizon" }},
+ "message-text": "i need a #verizon phone like nowwwww! :("
+ },
+ {
+ "tweetid": "1024",
+ "user": {
+ "screen-name": "miriamorous",
+ "lang": "en",
+ "friends_count": 69,
+ "statuses_count": 1068,
+ "name": "Miriam Songco",
+ "followers_count": 78
+ },
+ "send-time": "2010-02-21T11:11:43-08:00",
+ "referred-topics": {{ "commercials", "verizon", "att" }},
+ "message-text": "#verizon & #att #commercials, so competitive"
+ },
+ {
+ "tweetid": "1025",
+ "user": {
+ "screen-name": "dj33",
+ "lang": "en",
+ "friends_count": 96,
+ "statuses_count": 1696,
+ "name": "Don Jango",
+ "followers_count": 22
+ },
+ "send-time": "2010-02-21T12:38:44-05:00",
+ "referred-topics": {{ "charlotte" }},
+ "message-text": "Chillin at dca waiting for 900am flight to #charlotte and from there to providenciales"
+ },
+ {
+ "tweetid": "1026",
+ "user": {
+ "screen-name": "reallyleila",
+ "lang": "en",
+ "friends_count": 106,
+ "statuses_count": 107,
+ "name": "Leila Samii",
+ "followers_count": 52
+ },
+ "send-time": "2010-02-21T21:31:57-06:00",
+ "referred-topics": {{ "verizon", "at&t", "iphone" }},
+ "message-text": "I think a switch from #verizon to #at&t may be in my near future... my smartphone is like a land line compared to the #iphone!"
+ }
+}}
+return $tweets
\ No newline at end of file
diff --git a/asterix-app/src/test/resources/runtimets/results/open-closed/query-issue29.adm b/asterix-app/src/test/resources/runtimets/results/open-closed/query-issue29.adm
new file mode 100644
index 0000000..3d2819e
--- /dev/null
+++ b/asterix-app/src/test/resources/runtimets/results/open-closed/query-issue29.adm
@@ -0,0 +1 @@
+{{ { "tweetid": "1023", "user": { "screen-name": "dflynn24", "lang": "en", "friends_count": 46, "statuses_count": 987, "name": "danielle flynn", "followers_count": 47 }, "sender-location": "40.904177,-72.958996", "send-time": "2010-02-21T11:56:02-05:00", "referred-topics": {{ "verizon" }}, "message-text": "i need a #verizon phone like nowwwww! :(" }, { "tweetid": "1024", "user": { "screen-name": "miriamorous", "lang": "en", "friends_count": 69, "statuses_count": 1068, "name": "Miriam Songco", "followers_count": 78 }, "send-time": "2010-02-21T11:11:43-08:00", "referred-topics": {{ "commercials", "verizon", "att" }}, "message-text": "#verizon & #att #commercials, so competitive" }, { "tweetid": "1025", "user": { "screen-name": "dj33", "lang": "en", "friends_count": 96, "statuses_count": 1696, "name": "Don Jango", "followers_count": 22 }, "send-time": "2010-02-21T12:38:44-05:00", "referred-topics": {{ "charlotte" }}, "message-text": "Chillin at dca waiting for 900am flight to #charlotte and from there to providenciales" }, { "tweetid": "1026", "user": { "screen-name": "reallyleila", "lang": "en", "friends_count": 106, "statuses_count": 107, "name": "Leila Samii", "followers_count": 52 }, "send-time": "2010-02-21T21:31:57-06:00", "referred-topics": {{ "verizon", "at&t", "iphone" }}, "message-text": "I think a switch from #verizon to #at&t may be in my near future... my smartphone is like a land line compared to the #iphone!" } }}
diff --git a/asterix-om/src/main/java/edu/uci/ics/asterix/runtime/pointables/printer/AListPrinter.java b/asterix-om/src/main/java/edu/uci/ics/asterix/runtime/pointables/printer/AListPrinter.java
index e20b1059a..5e38f93 100644
--- a/asterix-om/src/main/java/edu/uci/ics/asterix/runtime/pointables/printer/AListPrinter.java
+++ b/asterix-om/src/main/java/edu/uci/ics/asterix/runtime/pointables/printer/AListPrinter.java
@@ -57,7 +57,7 @@
//print the beginning part
ps.print(leftParen);
- // print record 0 to n-2
+ // print item 0 to n-2
for (int i = 0; i < items.size() - 1; i++) {
IVisitablePointable itemTypeTag = itemTags.get(i);
IVisitablePointable item = items.get(i);
@@ -69,7 +69,7 @@
ps.print(COMMA);
}
- // print record n-1
+ // print item n-1
if (items.size() > 0) {
IVisitablePointable itemTypeTag = itemTags.get(itemTags.size() - 1);
IVisitablePointable item = items.get(items.size() - 1);
diff --git a/asterix-om/src/main/java/edu/uci/ics/asterix/runtime/pointables/printer/ARecordPrinter.java b/asterix-om/src/main/java/edu/uci/ics/asterix/runtime/pointables/printer/ARecordPrinter.java
index b0b3dfa..86d502d 100644
--- a/asterix-om/src/main/java/edu/uci/ics/asterix/runtime/pointables/printer/ARecordPrinter.java
+++ b/asterix-om/src/main/java/edu/uci/ics/asterix/runtime/pointables/printer/ARecordPrinter.java
@@ -55,7 +55,7 @@
// print the beginning part
ps.print(LEFT_PAREN);
- // print record 0 to n-2
+ // print field 0 to n-2
for (int i = 0; i < fieldNames.size() - 1; i++) {
IVisitablePointable itemTypeTag = fieldTags.get(i);
IVisitablePointable item = fieldValues.get(i);
@@ -73,7 +73,7 @@
ps.print(COMMA);
}
- // print record n-1
+ // print field n-1
if (fieldValues.size() > 0) {
IVisitablePointable itemTypeTag = fieldTags.get(fieldTags.size() - 1);
IVisitablePointable item = fieldValues.get(fieldValues.size() - 1);