[ASTERIXDB-2689][FUN] Make field-access-nested return MISSING on wrong args
- user model changes: no
- storage format changes: no
- interface changes: no
Details:
Make field-access-nested return MISSING on wrong args
Change-Id: I59ba234e352408e1017e879443a22d00d3c2262a
Reviewed-on: https://asterix-gerrit.ics.uci.edu/c/asterixdb/+/9747
Integration-Tests: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
Tested-by: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
Reviewed-by: Ali Alsuliman <ali.al.solaiman@gmail.com>
Reviewed-by: Dmitry Lychagin <dmitry.lychagin@couchbase.com>
diff --git a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/FieldAccessNestedResultType.java b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/FieldAccessNestedResultType.java
index 2f3965d..04f23d4 100644
--- a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/FieldAccessNestedResultType.java
+++ b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/FieldAccessNestedResultType.java
@@ -25,7 +25,6 @@
import org.apache.asterix.om.base.AString;
import org.apache.asterix.om.base.IAObject;
import org.apache.asterix.om.constants.AsterixConstantValue;
-import org.apache.asterix.om.exceptions.TypeMismatchException;
import org.apache.asterix.om.typecomputer.base.AbstractResultTypeComputer;
import org.apache.asterix.om.types.AOrderedListType;
import org.apache.asterix.om.types.ARecordType;
@@ -37,8 +36,6 @@
import org.apache.hyracks.algebricks.core.algebra.base.LogicalExpressionTag;
import org.apache.hyracks.algebricks.core.algebra.expressions.AbstractFunctionCallExpression;
import org.apache.hyracks.algebricks.core.algebra.expressions.ConstantExpression;
-import org.apache.hyracks.algebricks.core.algebra.functions.FunctionIdentifier;
-import org.apache.hyracks.api.exceptions.SourceLocation;
public class FieldAccessNestedResultType extends AbstractResultTypeComputer {
public static final FieldAccessNestedResultType INSTANCE = new FieldAccessNestedResultType();
@@ -47,34 +44,6 @@
}
@Override
- protected void checkArgType(FunctionIdentifier funcId, int argIndex, IAType type, SourceLocation sourceLoc)
- throws AlgebricksException {
- ATypeTag actualTypeTag = type.getTypeTag();
- if (argIndex == 0 && actualTypeTag != ATypeTag.OBJECT) {
- throw new TypeMismatchException(sourceLoc, actualTypeTag, ATypeTag.OBJECT);
- }
- if (argIndex == 1) {
- switch (actualTypeTag) {
- case STRING:
- break;
- case ARRAY:
- checkOrderedList(type, sourceLoc);
- break;
- default:
- throw new TypeMismatchException(sourceLoc, actualTypeTag, ATypeTag.STRING, ATypeTag.ARRAY);
- }
- }
- }
-
- private void checkOrderedList(IAType type, SourceLocation sourceLoc) throws AlgebricksException {
- AOrderedListType listType = (AOrderedListType) type;
- ATypeTag itemTypeTag = listType.getItemType().getTypeTag();
- if (itemTypeTag != ATypeTag.STRING && itemTypeTag != ATypeTag.ANY) {
- throw new TypeMismatchException(sourceLoc, itemTypeTag, ATypeTag.STRING, ATypeTag.ANY);
- }
- }
-
- @Override
protected IAType getResultType(ILogicalExpression expr, IAType... strippedInputTypes) throws AlgebricksException {
IAType firstArgType = strippedInputTypes[0];
if (firstArgType.getTypeTag() != ATypeTag.OBJECT) {
@@ -88,12 +57,15 @@
ConstantExpression ce = (ConstantExpression) arg1;
IAObject v = ((AsterixConstantValue) ce.getValue()).getObject();
List<String> fieldPath = new ArrayList<>();
- if (v.getType().getTypeTag() == ATypeTag.ARRAY) {
+ ATypeTag tag = v.getType().getTypeTag();
+ if (tag == ATypeTag.ARRAY && ((AOrderedListType) v.getType()).getItemType().getTypeTag() == ATypeTag.STRING) {
for (int i = 0; i < ((AOrderedList) v).size(); i++) {
fieldPath.add(((AString) ((AOrderedList) v).getItem(i)).getStringValue());
}
- } else {
+ } else if (tag == ATypeTag.STRING) {
fieldPath.add(((AString) v).getStringValue());
+ } else {
+ return BuiltinType.ANY;
}
ARecordType recType = (ARecordType) firstArgType;
IAType fieldType = recType.getSubFieldType(fieldPath);
diff --git a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/records/FieldAccessNestedDescriptor.java b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/records/FieldAccessNestedDescriptor.java
index 3871fa2..27be285 100644
--- a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/records/FieldAccessNestedDescriptor.java
+++ b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/records/FieldAccessNestedDescriptor.java
@@ -63,6 +63,6 @@
@Override
public IScalarEvaluatorFactory createEvaluatorFactory(IScalarEvaluatorFactory[] args) {
- return new FieldAccessNestedEvalFactory(args[0], recType, fldName, sourceLoc);
+ return new FieldAccessNestedEvalFactory(args[0], recType, fldName, sourceLoc, getIdentifier());
}
}
diff --git a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/records/FieldAccessNestedEvalFactory.java b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/records/FieldAccessNestedEvalFactory.java
index ef958f1..30f3fde 100644
--- a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/records/FieldAccessNestedEvalFactory.java
+++ b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/records/FieldAccessNestedEvalFactory.java
@@ -29,6 +29,7 @@
import org.apache.asterix.om.base.AMissing;
import org.apache.asterix.om.base.ANull;
import org.apache.asterix.om.base.AString;
+import org.apache.asterix.om.exceptions.ExceptionUtil;
import org.apache.asterix.om.types.ARecordType;
import org.apache.asterix.om.types.ATypeTag;
import org.apache.asterix.om.types.AUnionType;
@@ -39,7 +40,7 @@
import org.apache.asterix.om.utils.NonTaggedFormatUtil;
import org.apache.asterix.om.utils.RecordUtil;
import org.apache.asterix.runtime.evaluators.functions.PointableHelper;
-import org.apache.asterix.runtime.exceptions.TypeMismatchException;
+import org.apache.hyracks.algebricks.core.algebra.functions.FunctionIdentifier;
import org.apache.hyracks.algebricks.runtime.base.IEvaluatorContext;
import org.apache.hyracks.algebricks.runtime.base.IScalarEvaluator;
import org.apache.hyracks.algebricks.runtime.base.IScalarEvaluatorFactory;
@@ -62,13 +63,15 @@
private final ARecordType recordType;
private final List<String> fieldPath;
private final SourceLocation sourceLoc;
+ private final FunctionIdentifier funID;
public FieldAccessNestedEvalFactory(IScalarEvaluatorFactory recordEvalFactory, ARecordType recordType,
- List<String> fldName, SourceLocation sourceLoc) {
+ List<String> fldName, SourceLocation sourceLoc, FunctionIdentifier funID) {
this.recordEvalFactory = recordEvalFactory;
this.recordType = recordType;
this.fieldPath = fldName;
this.sourceLoc = sourceLoc;
+ this.funID = funID;
}
@Override
@@ -79,7 +82,7 @@
BinaryHashFunctionFactoryProvider.UTF8STRING_POINTABLE_INSTANCE.createBinaryHashFunction();
private final IBinaryComparator fieldNameComparator =
BinaryComparatorFactoryProvider.UTF8STRING_POINTABLE_INSTANCE.createBinaryComparator();
- private ArrayBackedValueStorage resultStorage = new ArrayBackedValueStorage();
+ private final ArrayBackedValueStorage resultStorage = new ArrayBackedValueStorage();
private final DataOutput out = resultStorage.getDataOutput();
private final ByteArrayAccessibleOutputStream subRecordTmpStream = new ByteArrayAccessibleOutputStream();
@@ -125,13 +128,14 @@
}
byte[] serRecord = inputArg0.getByteArray();
- int offset = inputArg0.getStartOffset();
- int start = offset;
+ int start = inputArg0.getStartOffset();
int len = inputArg0.getLength();
if (serRecord[start] != ATypeTag.SERIALIZED_RECORD_TYPE_TAG) {
- throw new TypeMismatchException(sourceLoc, serRecord[start],
- ATypeTag.SERIALIZED_RECORD_TYPE_TAG);
+ ExceptionUtil.warnTypeMismatch(ctx, sourceLoc, funID, serRecord[start], 0, ATypeTag.OBJECT);
+ missingSerde.serialize(AMissing.MISSING, out);
+ result.set(resultStorage);
+ return;
}
int subFieldIndex = -1;
@@ -143,7 +147,6 @@
recTypeInfos[0].reset(recordType);
ATypeTag subTypeTag = ATypeTag.MISSING;
- boolean openField = false;
int pathIndex = 0;
// Moving through closed fields first.
@@ -153,12 +156,13 @@
subType = ((AUnionType) subType).getActualType();
byte serializedTypeTag = subType.getTypeTag().serialize();
if (serializedTypeTag != ATypeTag.SERIALIZED_RECORD_TYPE_TAG) {
- throw new TypeMismatchException(sourceLoc, serializedTypeTag,
- ATypeTag.SERIALIZED_RECORD_TYPE_TAG);
+ ExceptionUtil.warnTypeMismatch(ctx, sourceLoc, funID, serializedTypeTag, 0,
+ ATypeTag.OBJECT);
+ missingSerde.serialize(AMissing.MISSING, out);
+ result.set(resultStorage);
+ return;
}
- if (subType.getTypeTag() == ATypeTag.OBJECT) {
- recTypeInfos[pathIndex].reset((ARecordType) subType);
- }
+ recTypeInfos[pathIndex].reset((ARecordType) subType);
}
subFieldIndex = recTypeInfos[pathIndex].getFieldIndex(fieldPointables[pathIndex].getByteArray(),
fieldPointables[pathIndex].getStartOffset() + 1,
@@ -209,12 +213,15 @@
// type check
if (pathIndex < fieldPointables.length - 1
&& serRecord[start] != ATypeTag.SERIALIZED_RECORD_TYPE_TAG) {
- throw new TypeMismatchException(sourceLoc, serRecord[start],
- ATypeTag.SERIALIZED_RECORD_TYPE_TAG);
+ ExceptionUtil.warnTypeMismatch(ctx, sourceLoc, funID, serRecord[start], 0, ATypeTag.OBJECT);
+ missingSerde.serialize(AMissing.MISSING, out);
+ result.set(resultStorage);
+ return;
}
}
// Moving through open fields after we hit the first open field.
+ boolean openField = false;
for (; pathIndex < fieldPointables.length; pathIndex++) {
openField = true;
subFieldOffset = ARecordSerializerDeserializer.getFieldOffsetByName(serRecord, start, len,
@@ -245,8 +252,10 @@
return;
}
if (serRecord[start] != ATypeTag.SERIALIZED_RECORD_TYPE_TAG) {
- throw new TypeMismatchException(sourceLoc, serRecord[start],
- ATypeTag.SERIALIZED_RECORD_TYPE_TAG);
+ ExceptionUtil.warnTypeMismatch(ctx, sourceLoc, funID, serRecord[start], 0, ATypeTag.OBJECT);
+ missingSerde.serialize(AMissing.MISSING, out);
+ result.set(resultStorage);
+ return;
}
}
// emit the final result.
diff --git a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/records/GetRecordFieldValueEvalFactory.java b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/records/GetRecordFieldValueEvalFactory.java
index d6c0e21..f8dacfa 100644
--- a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/records/GetRecordFieldValueEvalFactory.java
+++ b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/records/GetRecordFieldValueEvalFactory.java
@@ -98,11 +98,14 @@
byte[] serFldName = inputArg1.getByteArray();
int serFldNameOffset = inputArg1.getStartOffset();
int serFldNameLen = inputArg1.getLength();
+ if (serFldName[serFldNameOffset] != ATypeTag.SERIALIZED_STRING_TYPE_TAG) {
+ throw new TypeMismatchException(sourceLoc, BuiltinFunctions.GET_RECORD_FIELD_VALUE, 0,
+ serFldName[serFldNameOffset], ATypeTag.SERIALIZED_STRING_TYPE_TAG);
+ }
byte[] serRecord = inputArg0.getByteArray();
int serRecordOffset = inputArg0.getStartOffset();
int serRecordLen = inputArg0.getLength();
-
if (serRecord[serRecordOffset] != ATypeTag.SERIALIZED_RECORD_TYPE_TAG) {
throw new TypeMismatchException(sourceLoc, BuiltinFunctions.GET_RECORD_FIELD_VALUE, 0,
serRecord[serRecordOffset], ATypeTag.SERIALIZED_RECORD_TYPE_TAG);
diff --git a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/functions/FunctionTypeInferers.java b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/functions/FunctionTypeInferers.java
index ebb0717..2af4de5 100644
--- a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/functions/FunctionTypeInferers.java
+++ b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/functions/FunctionTypeInferers.java
@@ -163,7 +163,7 @@
public void infer(ILogicalExpression expr, IFunctionDescriptor fd, IVariableTypeEnvironment context,
CompilerProperties compilerProps) throws AlgebricksException {
AbstractFunctionCallExpression fce = (AbstractFunctionCallExpression) expr;
- IAType t = (IAType) context.getType(fce.getArguments().get(0).getValue());
+ // arg 1 should always be a constant array of strings
AOrderedList fieldPath =
(AOrderedList) (((AsterixConstantValue) ((ConstantExpression) fce.getArguments().get(1).getValue())
.getValue()).getObject());
@@ -171,17 +171,13 @@
for (int i = 0; i < fieldPath.size(); i++) {
listFieldPath.add(((AString) fieldPath.getItem(i)).getStringValue());
}
-
- // TODO(ali): I guess this may not work as well if t happens to be UNION(record), not sure if it ever does
+ IAType t = TypeComputeUtils.getActualType((IAType) context.getType(fce.getArguments().get(0).getValue()));
switch (t.getTypeTag()) {
case OBJECT:
fd.setImmutableStates(t, listFieldPath);
break;
- case ANY:
- fd.setImmutableStates(RecordUtil.FULLY_OPEN_RECORD_TYPE, listFieldPath);
- break;
default:
- fd.setImmutableStates(null, listFieldPath);
+ fd.setImmutableStates(RecordUtil.FULLY_OPEN_RECORD_TYPE, listFieldPath);
break;
}
}