use of org.apache.hyracks.algebricks.common.exceptions.AlgebricksException in project asterixdb by apache.
the class LangExpressionToPlanTranslator method translateLoad.
@Override
public ILogicalPlan translateLoad(ICompiledDmlStatement stmt) throws AlgebricksException {
CompiledLoadFromFileStatement clffs = (CompiledLoadFromFileStatement) stmt;
Dataset dataset = metadataProvider.findDataset(clffs.getDataverseName(), clffs.getDatasetName());
if (dataset == null) {
// This would never happen since we check for this in AqlTranslator
throw new AlgebricksException("Unable to load dataset " + clffs.getDatasetName() + " since it does not exist");
}
IAType itemType = metadataProvider.findType(dataset.getItemTypeDataverseName(), dataset.getItemTypeName());
IAType metaItemType = metadataProvider.findType(dataset.getMetaItemTypeDataverseName(), dataset.getMetaItemTypeName());
DatasetDataSource targetDatasource = validateDatasetInfo(metadataProvider, stmt.getDataverseName(), stmt.getDatasetName());
List<List<String>> partitionKeys = targetDatasource.getDataset().getPrimaryKeys();
if (dataset.hasMetaPart()) {
throw new AlgebricksException(dataset.getDatasetName() + ": load dataset is not supported on Datasets with Meta records");
}
LoadableDataSource lds;
try {
lds = new LoadableDataSource(dataset, itemType, metaItemType, clffs.getAdapter(), clffs.getProperties());
} catch (IOException e) {
throw new AlgebricksException(e);
}
// etsOp is a dummy input operator used to keep the compiler happy. it
// could be removed but would result in
// the need to fix many rewrite rules that assume that datasourcescan
// operators always have input.
ILogicalOperator etsOp = new EmptyTupleSourceOperator();
// Add a logical variable for the record.
List<LogicalVariable> payloadVars = new ArrayList<>();
payloadVars.add(context.newVar());
// Create a scan operator and make the empty tuple source its input
DataSourceScanOperator dssOp = new DataSourceScanOperator(payloadVars, lds);
dssOp.getInputs().add(new MutableObject<>(etsOp));
ILogicalExpression payloadExpr = new VariableReferenceExpression(payloadVars.get(0));
Mutable<ILogicalExpression> payloadRef = new MutableObject<>(payloadExpr);
// Creating the assign to extract the PK out of the record
ArrayList<LogicalVariable> pkVars = new ArrayList<>();
ArrayList<Mutable<ILogicalExpression>> pkExprs = new ArrayList<>();
List<Mutable<ILogicalExpression>> varRefsForLoading = new ArrayList<>();
LogicalVariable payloadVar = payloadVars.get(0);
for (List<String> keyFieldName : partitionKeys) {
PlanTranslationUtil.prepareVarAndExpression(keyFieldName, payloadVar, pkVars, pkExprs, varRefsForLoading, context);
}
AssignOperator assign = new AssignOperator(pkVars, pkExprs);
assign.getInputs().add(new MutableObject<>(dssOp));
// If the input is pre-sorted, we set the ordering property explicitly in the assign
if (clffs.alreadySorted()) {
List<OrderColumn> orderColumns = new ArrayList<>();
for (int i = 0; i < pkVars.size(); ++i) {
orderColumns.add(new OrderColumn(pkVars.get(i), OrderKind.ASC));
}
assign.setExplicitOrderingProperty(new LocalOrderProperty(orderColumns));
}
List<String> additionalFilteringField = DatasetUtil.getFilterField(targetDatasource.getDataset());
List<LogicalVariable> additionalFilteringVars;
List<Mutable<ILogicalExpression>> additionalFilteringAssignExpressions;
List<Mutable<ILogicalExpression>> additionalFilteringExpressions = null;
AssignOperator additionalFilteringAssign = null;
if (additionalFilteringField != null) {
additionalFilteringVars = new ArrayList<>();
additionalFilteringAssignExpressions = new ArrayList<>();
additionalFilteringExpressions = new ArrayList<>();
PlanTranslationUtil.prepareVarAndExpression(additionalFilteringField, payloadVar, additionalFilteringVars, additionalFilteringAssignExpressions, additionalFilteringExpressions, context);
additionalFilteringAssign = new AssignOperator(additionalFilteringVars, additionalFilteringAssignExpressions);
}
InsertDeleteUpsertOperator insertOp = new InsertDeleteUpsertOperator(targetDatasource, payloadRef, varRefsForLoading, InsertDeleteUpsertOperator.Kind.INSERT, true);
insertOp.setAdditionalFilteringExpressions(additionalFilteringExpressions);
if (additionalFilteringAssign != null) {
additionalFilteringAssign.getInputs().add(new MutableObject<>(assign));
insertOp.getInputs().add(new MutableObject<>(additionalFilteringAssign));
} else {
insertOp.getInputs().add(new MutableObject<>(assign));
}
ILogicalOperator leafOperator = new SinkOperator();
leafOperator.getInputs().add(new MutableObject<>(insertOp));
return new ALogicalPlanImpl(new MutableObject<>(leafOperator));
}
use of org.apache.hyracks.algebricks.common.exceptions.AlgebricksException in project asterixdb by apache.
the class StaticTypeCastUtil method rewriteFuncExpr.
/**
* This method is to recursively enforce required types, for the list type and the record type.
* The List constructor is very special because
* 1. a nested list in a list is of type List<ANY>;
* 2. a nested record in a list is of type Open_Record{}.
* The open record constructor is very special because
* 1. a nested list in the open part is of type List<ANY>;
* 2. a nested record in the open part is of type Open_Record{}.
* However, the bottom-up type inference (InferTypeRule in algebricks) did not infer that so we need this method to enforce the type.
* We do not want to break the generality of algebricks so this method is called in an ASTERIX rule: @ IntroduceStaticTypeCastRule} .
*
* @param funcExpr
* the function expression whose type needs to be top-down enforced
* @param reqType
* the required type inferred from parent operators/expressions
* @param inputType
* the current inferred
* @param env
* the type environment
* @return true if the type is casted; otherwise, false.
* @throws AlgebricksException
*/
public static boolean rewriteFuncExpr(AbstractFunctionCallExpression funcExpr, IAType reqType, IAType inputType, IVariableTypeEnvironment env) throws AlgebricksException {
/**
* sanity check: if there are list(ordered or unordered)/record variable expressions in the funcExpr, we will not do STATIC type casting
* because they are not "statically cast-able".
* instead, the record will be dynamically casted at the runtime
*/
if (funcExpr.getFunctionIdentifier() == BuiltinFunctions.UNORDERED_LIST_CONSTRUCTOR) {
if (reqType.equals(BuiltinType.ANY)) {
reqType = DefaultOpenFieldType.NESTED_OPEN_AUNORDERED_LIST_TYPE;
}
return rewriteListFuncExpr(funcExpr, (AbstractCollectionType) reqType, (AbstractCollectionType) inputType, env);
} else if (funcExpr.getFunctionIdentifier() == BuiltinFunctions.ORDERED_LIST_CONSTRUCTOR) {
if (reqType.equals(BuiltinType.ANY)) {
reqType = DefaultOpenFieldType.NESTED_OPEN_AORDERED_LIST_TYPE;
}
return rewriteListFuncExpr(funcExpr, (AbstractCollectionType) reqType, (AbstractCollectionType) inputType, env);
} else if (inputType.getTypeTag().equals(ATypeTag.OBJECT)) {
if (reqType.equals(BuiltinType.ANY)) {
reqType = DefaultOpenFieldType.NESTED_OPEN_RECORD_TYPE;
}
return rewriteRecordFuncExpr(funcExpr, (ARecordType) reqType, (ARecordType) inputType, env);
} else {
List<Mutable<ILogicalExpression>> args = funcExpr.getArguments();
boolean changed = false;
for (Mutable<ILogicalExpression> arg : args) {
ILogicalExpression argExpr = arg.getValue();
if (argExpr.getExpressionTag() == LogicalExpressionTag.FUNCTION_CALL) {
AbstractFunctionCallExpression argFuncExpr = (AbstractFunctionCallExpression) argExpr;
IAType exprType = (IAType) env.getType(argFuncExpr);
changed = changed || rewriteFuncExpr(argFuncExpr, exprType, exprType, env);
}
}
if (!compatible(reqType, inputType)) {
throw new AlgebricksException("type mismatch, required: " + reqType.toString() + " actual: " + inputType.toString());
}
return changed;
}
}
use of org.apache.hyracks.algebricks.common.exceptions.AlgebricksException 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;
}
use of org.apache.hyracks.algebricks.common.exceptions.AlgebricksException in project asterixdb by apache.
the class TypeUtil method createEnforcedType.
/**
* Merges typed index fields with specified recordType, allowing indexed fields to be optional.
* I.e. the type { "personId":int32, "name": string, "address" : { "street": string } } with typed indexes
* on age:int32, address.state:string will be merged into type { "personId":int32, "name": string,
* "age": int32? "address" : { "street": string, "state": string? } } Used by open indexes to enforce
* the type of an indexed record
*/
public static Pair<ARecordType, ARecordType> createEnforcedType(ARecordType recordType, ARecordType metaType, List<Index> indexes) throws AlgebricksException {
ARecordType enforcedRecordType = recordType;
ARecordType enforcedMetaType = metaType;
for (Index index : indexes) {
if (!index.isSecondaryIndex() || !index.isEnforcingKeyFileds()) {
continue;
}
if (index.hasMetaFields()) {
throw new AlgebricksException("Indexing an open field is only supported on the record part");
}
for (int i = 0; i < index.getKeyFieldNames().size(); i++) {
Deque<Pair<ARecordType, String>> nestedTypeStack = new ArrayDeque<>();
List<String> splits = index.getKeyFieldNames().get(i);
ARecordType nestedFieldType = enforcedRecordType;
boolean openRecords = false;
String bridgeName = nestedFieldType.getTypeName();
int j;
// Build the stack for the enforced type
for (j = 1; j < splits.size(); j++) {
nestedTypeStack.push(new Pair<>(nestedFieldType, splits.get(j - 1)));
bridgeName = nestedFieldType.getTypeName();
nestedFieldType = (ARecordType) enforcedRecordType.getSubFieldType(splits.subList(0, j));
if (nestedFieldType == null) {
openRecords = true;
break;
}
}
if (openRecords) {
// create the smallest record
enforcedRecordType = new ARecordType(splits.get(splits.size() - 2), new String[] { splits.get(splits.size() - 1) }, new IAType[] { AUnionType.createUnknownableType(index.getKeyFieldTypes().get(i)) }, true);
// create the open part of the nested field
for (int k = splits.size() - 3; k > (j - 2); k--) {
enforcedRecordType = new ARecordType(splits.get(k), new String[] { splits.get(k + 1) }, new IAType[] { AUnionType.createUnknownableType(enforcedRecordType) }, true);
}
// Bridge the gap
Pair<ARecordType, String> gapPair = nestedTypeStack.pop();
ARecordType parent = gapPair.first;
IAType[] parentFieldTypes = ArrayUtils.addAll(parent.getFieldTypes().clone(), new IAType[] { AUnionType.createUnknownableType(enforcedRecordType) });
enforcedRecordType = new ARecordType(bridgeName, ArrayUtils.addAll(parent.getFieldNames(), enforcedRecordType.getTypeName()), parentFieldTypes, true);
} else {
//Schema is closed all the way to the field
//enforced fields are either null or strongly typed
Map<String, IAType> recordNameTypesMap = TypeUtil.createRecordNameTypeMap(nestedFieldType);
// if a an enforced field already exists and the type is correct
IAType enforcedFieldType = recordNameTypesMap.get(splits.get(splits.size() - 1));
if (enforcedFieldType != null && enforcedFieldType.getTypeTag() == ATypeTag.UNION && ((AUnionType) enforcedFieldType).isUnknownableType()) {
enforcedFieldType = ((AUnionType) enforcedFieldType).getActualType();
}
if (enforcedFieldType != null && !ATypeHierarchy.canPromote(enforcedFieldType.getTypeTag(), index.getKeyFieldTypes().get(i).getTypeTag())) {
throw new AlgebricksException("Cannot enforce field " + index.getKeyFieldNames().get(i) + " to have type " + index.getKeyFieldTypes().get(i));
}
if (enforcedFieldType == null) {
recordNameTypesMap.put(splits.get(splits.size() - 1), AUnionType.createUnknownableType(index.getKeyFieldTypes().get(i)));
}
enforcedRecordType = new ARecordType(nestedFieldType.getTypeName(), recordNameTypesMap.keySet().toArray(new String[recordNameTypesMap.size()]), recordNameTypesMap.values().toArray(new IAType[recordNameTypesMap.size()]), nestedFieldType.isOpen());
}
// Create the enforced type for the nested fields in the schema, from the ground up
if (!nestedTypeStack.isEmpty()) {
while (!nestedTypeStack.isEmpty()) {
Pair<ARecordType, String> nestedTypePair = nestedTypeStack.pop();
ARecordType nestedRecType = nestedTypePair.first;
IAType[] nestedRecTypeFieldTypes = nestedRecType.getFieldTypes().clone();
nestedRecTypeFieldTypes[nestedRecType.getFieldIndex(nestedTypePair.second)] = enforcedRecordType;
enforcedRecordType = new ARecordType(nestedRecType.getTypeName() + "_enforced", nestedRecType.getFieldNames(), nestedRecTypeFieldTypes, nestedRecType.isOpen());
}
}
}
}
return new Pair<>(enforcedRecordType, enforcedMetaType);
}
use of org.apache.hyracks.algebricks.common.exceptions.AlgebricksException in project asterixdb by apache.
the class ExpressionTypeComputer method getTypeForFunction.
private IAType getTypeForFunction(AbstractFunctionCallExpression expr, IVariableTypeEnvironment env, IMetadataProvider<?, ?> mp) throws AlgebricksException {
FunctionIdentifier fi = expr.getFunctionIdentifier();
// Note: built-in functions + udfs
IResultTypeComputer rtc;
FunctionSignature signature = new FunctionSignature(fi.getNamespace(), fi.getName(), fi.getArity());
if (BuiltinFunctions.isBuiltinCompilerFunction(signature, true)) {
rtc = BuiltinFunctions.getResultTypeComputer(fi);
} else {
rtc = ((ExternalFunctionInfo) expr.getFunctionInfo()).getResultTypeComputer();
}
if (rtc == null) {
throw new AlgebricksException("Type computer missing for " + fi);
}
return rtc.computeType(expr, env, mp);
}
Aggregations