use of org.apache.hyracks.algebricks.core.algebra.expressions.ScalarFunctionCallExpression in project asterixdb by apache.
the class EquivalenceClassUtils method addEquivalenceClassesForPrimaryIndexAccess.
/**
* Adds equivalent classes for primary index accesses, including unnest-map for
* primary index access and data source scan through primary index ---
* one equivalent class between a primary key variable and a record field-access expression.
*
* @param operator
* , the primary index access operator.
* @param indexSearchVars
* , the returned variables from primary index access. The last variable
* is the record variable.
* @param recordType
* , the record type of an index payload record.
* @param metaRecordType
* , the type of a meta record associated with an index payload record.
* @param dataset
* , the accessed dataset.
* @param context
* , the optimization context.
* @throws AlgebricksException
*/
@SuppressWarnings("unchecked")
public static void addEquivalenceClassesForPrimaryIndexAccess(ILogicalOperator operator, List<LogicalVariable> indexSearchVars, ARecordType recordType, ARecordType metaRecordType, Dataset dataset, IOptimizationContext context) throws AlgebricksException {
if (dataset.getDatasetDetails().getDatasetType() != DatasetType.INTERNAL) {
return;
}
InternalDatasetDetails datasetDetails = (InternalDatasetDetails) dataset.getDatasetDetails();
List<List<String>> primaryKey = datasetDetails.getPrimaryKey();
Map<String, Integer> fieldNameToIndexMap = new HashMap<String, Integer>();
String[] fieldNames = recordType.getFieldNames();
for (int fieldIndex = 0; fieldIndex < fieldNames.length; ++fieldIndex) {
fieldNameToIndexMap.put(fieldNames[fieldIndex], fieldIndex);
}
boolean hasMeta = dataset.hasMetaPart();
Map<String, Integer> metaFieldNameToIndexMap = new HashMap<>();
if (hasMeta) {
String[] metaFieldNames = metaRecordType.getFieldNames();
for (int metaFieldIndex = 0; metaFieldIndex < metaFieldNames.length; ++metaFieldIndex) {
metaFieldNameToIndexMap.put(metaFieldNames[metaFieldIndex], metaFieldIndex);
}
}
List<Integer> keySourceIndicators = datasetDetails.getKeySourceIndicator();
LogicalVariable recordVar = hasMeta ? indexSearchVars.get(indexSearchVars.size() - 2) : indexSearchVars.get(indexSearchVars.size() - 1);
LogicalVariable metaRecordVar = hasMeta ? indexSearchVars.get(indexSearchVars.size() - 1) : null;
for (int pkIndex = 0; pkIndex < primaryKey.size(); ++pkIndex) {
LogicalVariable referredRecordVar = recordVar;
String pkFieldName = primaryKey.get(pkIndex).get(0);
int source = keySourceIndicators.get(pkIndex);
Integer fieldIndexInRecord;
if (source == 0) {
// The field is from the main record.
fieldIndexInRecord = fieldNameToIndexMap.get(pkFieldName);
} else {
// The field is from the auxiliary meta record.
referredRecordVar = metaRecordVar;
fieldIndexInRecord = metaFieldNameToIndexMap.get(pkFieldName);
}
LogicalVariable var = indexSearchVars.get(pkIndex);
ILogicalExpression expr = new ScalarFunctionCallExpression(FunctionUtil.getFunctionInfo(BuiltinFunctions.FIELD_ACCESS_BY_INDEX), new MutableObject<ILogicalExpression>(new VariableReferenceExpression(referredRecordVar)), new MutableObject<ILogicalExpression>(new ConstantExpression(new AsterixConstantValue(new AInt32(fieldIndexInRecord)))));
EquivalenceClass equivClass = new EquivalenceClass(Collections.singletonList(var), var, Collections.singletonList(expr));
Map<LogicalVariable, EquivalenceClass> equivalenceMap = context.getEquivalenceClassMap(operator);
if (equivalenceMap == null) {
equivalenceMap = new HashMap<LogicalVariable, EquivalenceClass>();
context.putEquivalenceClassMap(operator, equivalenceMap);
}
equivalenceMap.put(var, equivClass);
}
}
use of org.apache.hyracks.algebricks.core.algebra.expressions.ScalarFunctionCallExpression in project asterixdb by apache.
the class LangExpressionToPlanTranslator method visit.
@Override
public Pair<ILogicalOperator, LogicalVariable> visit(RecordConstructor rc, Mutable<ILogicalOperator> tupSource) throws CompilationException {
AbstractFunctionCallExpression f = new ScalarFunctionCallExpression(FunctionUtil.getFunctionInfo(BuiltinFunctions.OPEN_RECORD_CONSTRUCTOR));
LogicalVariable v1 = context.newVar();
AssignOperator a = new AssignOperator(v1, new MutableObject<>(f));
Mutable<ILogicalOperator> topOp = tupSource;
for (FieldBinding fb : rc.getFbList()) {
Pair<ILogicalExpression, Mutable<ILogicalOperator>> eo1 = langExprToAlgExpression(fb.getLeftExpr(), topOp);
f.getArguments().add(new MutableObject<>(eo1.first));
topOp = eo1.second;
Pair<ILogicalExpression, Mutable<ILogicalOperator>> eo2 = langExprToAlgExpression(fb.getRightExpr(), topOp);
f.getArguments().add(new MutableObject<>(eo2.first));
topOp = eo2.second;
}
a.getInputs().add(topOp);
return new Pair<>(a, v1);
}
use of org.apache.hyracks.algebricks.core.algebra.expressions.ScalarFunctionCallExpression in project asterixdb by apache.
the class LangExpressionToPlanTranslator method generateNoMatchedPrecedingWhenBranchesFilter.
// Generates the filter condition for whether a conditional branch should be executed.
protected Mutable<ILogicalExpression> generateNoMatchedPrecedingWhenBranchesFilter(List<ILogicalExpression> inputBooleanExprs) {
List<Mutable<ILogicalExpression>> arguments = new ArrayList<>();
for (ILogicalExpression inputBooleanExpr : inputBooleanExprs) {
// A NULL/MISSING valued WHEN expression does not lead to the corresponding THEN execution.
// Therefore, we should check a previous WHEN boolean condition is not unknown.
arguments.add(generateAndNotIsUnknownWrap(inputBooleanExpr));
}
Mutable<ILogicalExpression> hasBeenExecutedExprRef = new MutableObject<>(new ScalarFunctionCallExpression(FunctionUtil.getFunctionInfo(BuiltinFunctions.OR), arguments));
return new MutableObject<>(new ScalarFunctionCallExpression(FunctionUtil.getFunctionInfo(BuiltinFunctions.NOT), new ArrayList<>(Collections.singletonList(hasBeenExecutedExprRef))));
}
use of org.apache.hyracks.algebricks.core.algebra.expressions.ScalarFunctionCallExpression in project asterixdb by apache.
the class StaticTypeCastUtil method injectCastToRelaxType.
private static boolean injectCastToRelaxType(Mutable<ILogicalExpression> expRef, IAType inputFieldType, IVariableTypeEnvironment env) throws AlgebricksException {
ILogicalExpression argExpr = expRef.getValue();
List<LogicalVariable> parameterVars = new ArrayList<LogicalVariable>();
argExpr.getUsedVariables(parameterVars);
// we need to handle open fields recursively by their default
// types
// for list, their item type is any
// for record, their
boolean castInjected = false;
if (argExpr.getExpressionTag() == LogicalExpressionTag.FUNCTION_CALL || argExpr.getExpressionTag() == LogicalExpressionTag.VARIABLE) {
IAType reqFieldType = inputFieldType;
// do not enforce nested type in the case of no-used variables
switch(inputFieldType.getTypeTag()) {
case OBJECT:
reqFieldType = DefaultOpenFieldType.NESTED_OPEN_RECORD_TYPE;
break;
case ARRAY:
reqFieldType = DefaultOpenFieldType.NESTED_OPEN_AORDERED_LIST_TYPE;
break;
case MULTISET:
reqFieldType = DefaultOpenFieldType.NESTED_OPEN_AUNORDERED_LIST_TYPE;
break;
default:
break;
}
// do not enforce nested type in the case of no-used variables
if (!inputFieldType.equals(reqFieldType) && !parameterVars.isEmpty()) {
//inject dynamic type casting
injectCastFunction(FunctionUtil.getFunctionInfo(BuiltinFunctions.CAST_TYPE), reqFieldType, inputFieldType, expRef, argExpr);
castInjected = true;
}
//recursively rewrite function arguments
if (argExpr.getExpressionTag() == LogicalExpressionTag.FUNCTION_CALL && TypeCastUtils.getRequiredType((AbstractFunctionCallExpression) argExpr) == null && reqFieldType != null) {
if (castInjected) {
//rewrite the arg expression inside the dynamic cast
ScalarFunctionCallExpression argFunc = (ScalarFunctionCallExpression) argExpr;
rewriteFuncExpr(argFunc, inputFieldType, inputFieldType, env);
} else {
//rewrite arg
ScalarFunctionCallExpression argFunc = (ScalarFunctionCallExpression) argExpr;
rewriteFuncExpr(argFunc, reqFieldType, inputFieldType, env);
}
}
}
return castInjected;
}
use of org.apache.hyracks.algebricks.core.algebra.expressions.ScalarFunctionCallExpression in project asterixdb by apache.
the class StaticTypeCastUtil method staticRecordTypeCast.
/**
* This method statically cast the type of records from their current type to the required type.
*
* @param func
* The record constructor expression.
* @param reqType
* The required type.
* @param inputType
* The current type.
* @param env
* The type environment.
* @throws AlgebricksException
*/
private static boolean staticRecordTypeCast(AbstractFunctionCallExpression func, ARecordType reqType, ARecordType inputType, IVariableTypeEnvironment env) throws AlgebricksException {
if (!(func.getFunctionIdentifier() == BuiltinFunctions.OPEN_RECORD_CONSTRUCTOR || func.getFunctionIdentifier() == BuiltinFunctions.CLOSED_RECORD_CONSTRUCTOR)) {
return false;
}
IAType[] reqFieldTypes = reqType.getFieldTypes();
String[] reqFieldNames = reqType.getFieldNames();
IAType[] inputFieldTypes = inputType.getFieldTypes();
String[] inputFieldNames = inputType.getFieldNames();
int[] fieldPermutation = new int[reqFieldTypes.length];
boolean[] nullFields = new boolean[reqFieldTypes.length];
boolean[] openFields = new boolean[inputFieldTypes.length];
Arrays.fill(nullFields, false);
Arrays.fill(openFields, true);
Arrays.fill(fieldPermutation, -1);
// forward match: match from actual to required
boolean matched = false;
for (int i = 0; i < inputFieldNames.length; i++) {
String fieldName = inputFieldNames[i];
IAType fieldType = inputFieldTypes[i];
if (2 * i + 1 > func.getArguments().size()) {
// it is not a record constructor function
return false;
}
// 2*i+1 is the index of field value expression
ILogicalExpression arg = func.getArguments().get(2 * i + 1).getValue();
matched = false;
for (int j = 0; j < reqFieldNames.length; j++) {
String reqFieldName = reqFieldNames[j];
IAType reqFieldType = reqFieldTypes[j];
if (fieldName.equals(reqFieldName)) {
//type matched
if (fieldType.equals(reqFieldType)) {
fieldPermutation[j] = i;
openFields[i] = false;
matched = true;
if (arg.getExpressionTag() == LogicalExpressionTag.FUNCTION_CALL) {
ScalarFunctionCallExpression scalarFunc = (ScalarFunctionCallExpression) arg;
rewriteFuncExpr(scalarFunc, reqFieldType, fieldType, env);
}
break;
}
// match the optional field
if (NonTaggedFormatUtil.isOptional(reqFieldType)) {
IAType itemType = ((AUnionType) reqFieldType).getActualType();
reqFieldType = itemType;
if (fieldType.equals(BuiltinType.AMISSING) || fieldType.equals(itemType)) {
fieldPermutation[j] = i;
openFields[i] = false;
matched = true;
// rewrite record expr
if (arg.getExpressionTag() == LogicalExpressionTag.FUNCTION_CALL) {
ScalarFunctionCallExpression scalarFunc = (ScalarFunctionCallExpression) arg;
rewriteFuncExpr(scalarFunc, reqFieldType, fieldType, env);
}
break;
}
}
// delay that to runtime by calling the not-null function
if (NonTaggedFormatUtil.isOptional(fieldType)) {
IAType itemType = ((AUnionType) fieldType).getActualType();
if (reqFieldType.equals(itemType)) {
fieldPermutation[j] = i;
openFields[i] = false;
matched = true;
ScalarFunctionCallExpression notNullFunc = new ScalarFunctionCallExpression(FunctionUtil.getFunctionInfo(BuiltinFunctions.CHECK_UNKNOWN));
notNullFunc.getArguments().add(new MutableObject<ILogicalExpression>(arg));
//wrap the not null function to the original function
func.getArguments().get(2 * i + 1).setValue(notNullFunc);
break;
}
}
// match the record field: need cast
if (arg.getExpressionTag() == LogicalExpressionTag.FUNCTION_CALL) {
ScalarFunctionCallExpression scalarFunc = (ScalarFunctionCallExpression) arg;
rewriteFuncExpr(scalarFunc, reqFieldType, fieldType, env);
fieldPermutation[j] = i;
openFields[i] = false;
matched = true;
break;
}
}
}
// the input has extra fields
if (!matched && !reqType.isOpen()) {
throw new AlgebricksException("static type mismatch: the input record includes an extra closed field " + fieldName + ":" + fieldType + "! Please check the field name and type.");
}
}
// backward match: match from required to actual
for (int i = 0; i < reqFieldNames.length; i++) {
String reqFieldName = reqFieldNames[i];
IAType reqFieldType = reqFieldTypes[i];
matched = false;
for (int j = 0; j < inputFieldNames.length; j++) {
String fieldName = inputFieldNames[j];
IAType fieldType = inputFieldTypes[j];
if (!fieldName.equals(reqFieldName)) {
continue;
}
// the entry index of fieldPermuatons is req field index
if (!openFields[j]) {
matched = true;
break;
}
// match the optional field
if (!NonTaggedFormatUtil.isOptional(reqFieldType)) {
continue;
}
IAType itemType = ((AUnionType) reqFieldType).getActualType();
if (fieldType.equals(BuiltinType.AMISSING) || fieldType.equals(itemType)) {
matched = true;
break;
}
}
if (matched) {
continue;
}
if (NonTaggedFormatUtil.isOptional(reqFieldType)) {
// add a null field
nullFields[i] = true;
} else {
// no matched field in the input for a required closed field
if (inputType.isOpen()) {
//if the input type is open, return false, give that to dynamic type cast to defer the error to the runtime
return false;
} else {
throw new AlgebricksException("static type mismatch: the input record misses a required closed field " + reqFieldName + ":" + reqFieldType + "! Please check the field name and type.");
}
}
}
List<Mutable<ILogicalExpression>> arguments = func.getArguments();
List<Mutable<ILogicalExpression>> originalArguments = new ArrayList<Mutable<ILogicalExpression>>();
originalArguments.addAll(arguments);
arguments.clear();
// re-order the closed part and fill in null fields
for (int i = 0; i < fieldPermutation.length; i++) {
int pos = fieldPermutation[i];
if (pos >= 0) {
arguments.add(originalArguments.get(2 * pos));
arguments.add(originalArguments.get(2 * pos + 1));
}
if (nullFields[i]) {
// add a null field
arguments.add(new MutableObject<ILogicalExpression>(new ConstantExpression(new AsterixConstantValue(new AString(reqFieldNames[i])))));
arguments.add(new MutableObject<ILogicalExpression>(new ConstantExpression(new AsterixConstantValue(ANull.NULL))));
}
}
// add the open part
for (int i = 0; i < openFields.length; i++) {
if (openFields[i]) {
arguments.add(originalArguments.get(2 * i));
Mutable<ILogicalExpression> expRef = originalArguments.get(2 * i + 1);
injectCastToRelaxType(expRef, inputFieldTypes[i], env);
arguments.add(expRef);
}
}
return true;
}
Aggregations