Repository: asterixdb Updated Branches: refs/heads/master dba817c9b -> 5cdaa5d6a
http://git-wip-us.apache.org/repos/asf/asterixdb/blob/5cdaa5d6/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/visitor/GenerateColumnNameVisitor.java ---------------------------------------------------------------------- diff --git a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/visitor/GenerateColumnNameVisitor.java b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/visitor/GenerateColumnNameVisitor.java index 4e1ab1f..b945a40 100644 --- a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/visitor/GenerateColumnNameVisitor.java +++ b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/visitor/GenerateColumnNameVisitor.java @@ -47,7 +47,7 @@ public class GenerateColumnNameVisitor extends AbstractSqlppExpressionScopingVis @Override public Expression visit(Projection projection, ILangExpression arg) throws CompilationException { - if (!projection.star() && projection.getName() == null) { + if (!projection.star() && !projection.varStar() && projection.getName() == null) { projection.setName(SqlppVariableUtil.variableNameToDisplayedFieldName(context.newVariable().getValue())); } return super.visit(projection, arg); http://git-wip-us.apache.org/repos/asf/asterixdb/blob/5cdaa5d6/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/visitor/InlineColumnAliasVisitor.java ---------------------------------------------------------------------- diff --git a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/visitor/InlineColumnAliasVisitor.java b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/visitor/InlineColumnAliasVisitor.java index 270b366..fa049fe 100644 --- a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/visitor/InlineColumnAliasVisitor.java +++ b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/visitor/InlineColumnAliasVisitor.java @@ -130,9 +130,12 @@ public class InlineColumnAliasVisitor extends AbstractSqlppExpressionScopingVisi private Map<Expression, Expression> mapProjections(List<Projection> projections) { Map<Expression, Expression> exprMap = new HashMap<>(); for (Projection projection : projections) { - exprMap.put( - new VariableExpr(new VarIdentifier(SqlppVariableUtil.toInternalVariableName(projection.getName()))), - projection.getExpression()); + if (!projection.star() && !projection.varStar()) { + exprMap.put( + new VariableExpr( + new VarIdentifier(SqlppVariableUtil.toInternalVariableName(projection.getName()))), + projection.getExpression()); + } } return exprMap; } http://git-wip-us.apache.org/repos/asf/asterixdb/blob/5cdaa5d6/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/visitor/SqlppInlineUdfsVisitor.java ---------------------------------------------------------------------- diff --git a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/visitor/SqlppInlineUdfsVisitor.java b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/visitor/SqlppInlineUdfsVisitor.java index d1d95ac..db5b780 100644 --- a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/visitor/SqlppInlineUdfsVisitor.java +++ b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/visitor/SqlppInlineUdfsVisitor.java @@ -118,7 +118,7 @@ public class SqlppInlineUdfsVisitor extends AbstractInlineUdfsVisitor @Override public Boolean visit(Projection projection, List<FunctionDecl> funcs) throws CompilationException { - if (projection.star() == true) { + if (projection.star()) { return false; } Pair<Boolean, Expression> p = inlineUdfsInExpr(projection.getExpression(), funcs); http://git-wip-us.apache.org/repos/asf/asterixdb/blob/5cdaa5d6/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/DeepCopyVisitor.java ---------------------------------------------------------------------- diff --git a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/DeepCopyVisitor.java b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/DeepCopyVisitor.java index ffd63d4..1166148 100644 --- a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/DeepCopyVisitor.java +++ b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/DeepCopyVisitor.java @@ -131,7 +131,7 @@ public class DeepCopyVisitor extends AbstractSqlppQueryExpressionVisitor<ILangEx @Override public Projection visit(Projection projection, Void arg) throws CompilationException { return new Projection(projection.star() ? null : (Expression) projection.getExpression().accept(this, arg), - projection.getName(), projection.star(), projection.exprStar()); + projection.getName(), projection.star(), projection.varStar()); } @Override http://git-wip-us.apache.org/repos/asf/asterixdb/blob/5cdaa5d6/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/SqlppAstPrintVisitor.java ---------------------------------------------------------------------- diff --git a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/SqlppAstPrintVisitor.java b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/SqlppAstPrintVisitor.java index 09eaa59..5f6b75b 100644 --- a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/SqlppAstPrintVisitor.java +++ b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/SqlppAstPrintVisitor.java @@ -127,7 +127,7 @@ public class SqlppAstPrintVisitor extends QueryPrintVisitor implements ISqlppVis out.println(skip(step) + "*"); } else { projection.getExpression().accept(this, step); - out.println(skip(step) + projection.getName()); + out.println(skip(step) + (projection.varStar() ? ".*" : projection.getName())); } return null; } http://git-wip-us.apache.org/repos/asf/asterixdb/blob/5cdaa5d6/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/SqlppCloneAndSubstituteVariablesVisitor.java ---------------------------------------------------------------------- diff --git a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/SqlppCloneAndSubstituteVariablesVisitor.java b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/SqlppCloneAndSubstituteVariablesVisitor.java index 65e9255..0222e0e 100644 --- a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/SqlppCloneAndSubstituteVariablesVisitor.java +++ b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/SqlppCloneAndSubstituteVariablesVisitor.java @@ -197,7 +197,7 @@ public class SqlppCloneAndSubstituteVariablesVisitor extends CloneAndSubstituteV return new Pair<>(projection, env); } Projection newProjection = new Projection((Expression) projection.getExpression().accept(this, env).first, - projection.getName(), projection.star(), projection.exprStar()); + projection.getName(), projection.star(), projection.varStar()); return new Pair<>(newProjection, env); } http://git-wip-us.apache.org/repos/asf/asterixdb/blob/5cdaa5d6/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/SqlppFormatPrintVisitor.java ---------------------------------------------------------------------- diff --git a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/SqlppFormatPrintVisitor.java b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/SqlppFormatPrintVisitor.java index 51444e8..755cc69 100644 --- a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/SqlppFormatPrintVisitor.java +++ b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/SqlppFormatPrintVisitor.java @@ -126,9 +126,13 @@ public class SqlppFormatPrintVisitor extends FormatPrintVisitor implements ISqlp return null; } projection.getExpression().accept(this, step); - String name = projection.getName(); - if (name != null) { - out.print(" as " + name); + if (projection.varStar()) { + out.print(".* "); + } else { + String name = projection.getName(); + if (name != null) { + out.print(" as " + name); + } } return null; } http://git-wip-us.apache.org/repos/asf/asterixdb/blob/5cdaa5d6/asterixdb/asterix-lang-sqlpp/src/main/javacc/SQLPP.jj ---------------------------------------------------------------------- diff --git a/asterixdb/asterix-lang-sqlpp/src/main/javacc/SQLPP.jj b/asterixdb/asterix-lang-sqlpp/src/main/javacc/SQLPP.jj index a532a6b..7a99814 100644 --- a/asterixdb/asterix-lang-sqlpp/src/main/javacc/SQLPP.jj +++ b/asterixdb/asterix-lang-sqlpp/src/main/javacc/SQLPP.jj @@ -2477,15 +2477,12 @@ RecordConstructor RecordConstructor() throws ParseException: FieldBinding FieldBinding() throws ParseException: { - FieldBinding fb = new FieldBinding(); Expression left, right; } { left = Expression() <COLON> right = Expression() { - fb.setLeftExpr(left); - fb.setRightExpr(right); - return fb; + return new FieldBinding(left, right); } } @@ -2768,23 +2765,24 @@ Projection Projection() throws ParseException : Identifier identifier = null; String name = null; boolean star = false; - boolean exprStar = false; + boolean varStar = false; } { ( - LOOKAHEAD(2) - expr = Expression() ((<AS>)? name = Identifier())? - | expr = Expression() <DOT> <MUL> {exprStar = true; } - | <MUL> {star = true; } + <MUL> {star = true; } + | LOOKAHEAD(3) expr = VariableRef() <DOT> <MUL> {varStar = true; } + | expr = Expression() ((<AS>)? name = Identifier())? + { + if (name == null) { + String generatedColumnIdentifier = ExpressionToVariableUtil.getGeneratedIdentifier(expr, false); + if (generatedColumnIdentifier != null) { + name = SqlppVariableUtil.toUserDefinedName(generatedColumnIdentifier); + } + } + } ) { - if(!star && name == null){ - String generatedColumnIdentifier = ExpressionToVariableUtil.getGeneratedIdentifier(expr, false); - if(generatedColumnIdentifier != null){ - name = SqlppVariableUtil.toUserDefinedName(generatedColumnIdentifier); - } - } - return new Projection(expr, name, star, exprStar); + return new Projection(expr, name, star, varStar); } } http://git-wip-us.apache.org/repos/asf/asterixdb/blob/5cdaa5d6/asterixdb/asterix-om/src/main/java/org/apache/asterix/builders/RecordBuilder.java ---------------------------------------------------------------------- diff --git a/asterixdb/asterix-om/src/main/java/org/apache/asterix/builders/RecordBuilder.java b/asterixdb/asterix-om/src/main/java/org/apache/asterix/builders/RecordBuilder.java index 975b4f4..10863cd 100644 --- a/asterixdb/asterix-om/src/main/java/org/apache/asterix/builders/RecordBuilder.java +++ b/asterixdb/asterix-om/src/main/java/org/apache/asterix/builders/RecordBuilder.java @@ -310,4 +310,11 @@ public class RecordBuilder implements IARecordBuilder { return -1; } + public IBinaryHashFunction getFieldNameHashFunction() { + return utf8HashFunction; + } + + public IBinaryComparator getFieldNameComparator() { + return utf8Comparator; + } } http://git-wip-us.apache.org/repos/asf/asterixdb/blob/5cdaa5d6/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/functions/BuiltinFunctions.java ---------------------------------------------------------------------- diff --git a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/functions/BuiltinFunctions.java b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/functions/BuiltinFunctions.java index d749899..d920286 100644 --- a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/functions/BuiltinFunctions.java +++ b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/functions/BuiltinFunctions.java @@ -178,6 +178,10 @@ public class BuiltinFunctions { // objects public static final FunctionIdentifier RECORD_MERGE = new FunctionIdentifier(FunctionConstants.ASTERIX_NS, "object-merge", 2); + public static final FunctionIdentifier RECORD_CONCAT = + new FunctionIdentifier(FunctionConstants.ASTERIX_NS, "object-concat", FunctionIdentifier.VARARGS); + public static final FunctionIdentifier RECORD_CONCAT_STRICT = + new FunctionIdentifier(FunctionConstants.ASTERIX_NS, "object-concat-strict", FunctionIdentifier.VARARGS); public static final FunctionIdentifier REMOVE_FIELDS = new FunctionIdentifier(FunctionConstants.ASTERIX_NS, "object-remove-fields", 2); public static final FunctionIdentifier ADD_FIELDS = @@ -1174,6 +1178,8 @@ public class BuiltinFunctions { // objects addFunction(RECORD_MERGE, RecordMergeTypeComputer.INSTANCE, true); + addFunction(RECORD_CONCAT, OpenARecordTypeComputer.INSTANCE, true); + addPrivateFunction(RECORD_CONCAT_STRICT, OpenARecordTypeComputer.INSTANCE, true); addFunction(ADD_FIELDS, RecordAddFieldsTypeComputer.INSTANCE, true); addFunction(REMOVE_FIELDS, RecordRemoveFieldsTypeComputer.INSTANCE, true); addPrivateFunction(CLOSED_RECORD_CONSTRUCTOR, ClosedRecordConstructorResultType.INSTANCE, true); http://git-wip-us.apache.org/repos/asf/asterixdb/blob/5cdaa5d6/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/records/RecordConcatDescriptor.java ---------------------------------------------------------------------- diff --git a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/records/RecordConcatDescriptor.java b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/records/RecordConcatDescriptor.java new file mode 100644 index 0000000..0a3ba36 --- /dev/null +++ b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/records/RecordConcatDescriptor.java @@ -0,0 +1,67 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.asterix.runtime.evaluators.functions.records; + +import org.apache.asterix.om.functions.BuiltinFunctions; +import org.apache.asterix.om.functions.IFunctionDescriptor; +import org.apache.asterix.om.functions.IFunctionDescriptorFactory; +import org.apache.asterix.om.functions.IFunctionTypeInferer; +import org.apache.asterix.om.types.ARecordType; +import org.apache.asterix.runtime.evaluators.base.AbstractScalarFunctionDynamicDescriptor; +import org.apache.asterix.runtime.functions.FunctionTypeInferers; +import org.apache.hyracks.algebricks.core.algebra.functions.FunctionIdentifier; +import org.apache.hyracks.algebricks.runtime.base.IScalarEvaluatorFactory; + +/** + * Concatenates multiple records into one. Returns {@code null} if an argument is not a record. + */ +public class RecordConcatDescriptor extends AbstractScalarFunctionDynamicDescriptor { + + public static final IFunctionDescriptorFactory FACTORY = new IFunctionDescriptorFactory() { + @Override + public IFunctionDescriptor createFunctionDescriptor() { + return new RecordConcatDescriptor(); + } + + @Override + public IFunctionTypeInferer createFunctionTypeInferer() { + return new FunctionTypeInferers.RecordConcatTypeInferer(); + } + }; + + private static final long serialVersionUID = 1L; + + private ARecordType[] argTypes; + + @Override + public void setImmutableStates(Object... states) { + argTypes = (ARecordType[]) states; + } + + @Override + public IScalarEvaluatorFactory createEvaluatorFactory(final IScalarEvaluatorFactory[] args) { + return new RecordConcatEvalFactory(args, argTypes, false); + } + + @Override + public FunctionIdentifier getIdentifier() { + return BuiltinFunctions.RECORD_CONCAT; + } +} http://git-wip-us.apache.org/repos/asf/asterixdb/blob/5cdaa5d6/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/records/RecordConcatEvalFactory.java ---------------------------------------------------------------------- diff --git a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/records/RecordConcatEvalFactory.java b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/records/RecordConcatEvalFactory.java new file mode 100644 index 0000000..71f035e --- /dev/null +++ b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/records/RecordConcatEvalFactory.java @@ -0,0 +1,245 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.asterix.runtime.evaluators.functions.records; + +import java.io.DataOutput; +import java.io.IOException; +import java.util.BitSet; +import java.util.List; + +import org.apache.asterix.builders.RecordBuilder; +import org.apache.asterix.om.functions.BuiltinFunctions; +import org.apache.asterix.om.pointables.ARecordVisitablePointable; +import org.apache.asterix.om.pointables.base.DefaultOpenFieldType; +import org.apache.asterix.om.pointables.base.IVisitablePointable; +import org.apache.asterix.om.pointables.cast.ACastVisitor; +import org.apache.asterix.om.types.ARecordType; +import org.apache.asterix.om.types.ATypeTag; +import org.apache.asterix.om.types.IAType; +import org.apache.asterix.runtime.evaluators.functions.BinaryHashMap; +import org.apache.asterix.runtime.exceptions.TypeMismatchException; +import org.apache.hyracks.algebricks.common.utils.Triple; +import org.apache.hyracks.algebricks.runtime.base.IScalarEvaluator; +import org.apache.hyracks.algebricks.runtime.base.IScalarEvaluatorFactory; +import org.apache.hyracks.api.context.IHyracksTaskContext; +import org.apache.hyracks.api.exceptions.HyracksDataException; +import org.apache.hyracks.data.std.api.IPointable; +import org.apache.hyracks.data.std.primitive.VoidPointable; +import org.apache.hyracks.data.std.util.ArrayBackedValueStorage; +import org.apache.hyracks.data.std.util.BinaryEntry; +import org.apache.hyracks.dataflow.common.data.accessors.IFrameTupleReference; + +class RecordConcatEvalFactory implements IScalarEvaluatorFactory { + + private static final long serialVersionUID = 1L; + + private final IScalarEvaluatorFactory[] args; + + private final ARecordType[] argTypes; + + private final boolean failOnArgTypeMismatch; + + RecordConcatEvalFactory(IScalarEvaluatorFactory[] args, ARecordType[] argTypes, boolean failOnArgTypeMismatch) { + this.args = args; + this.argTypes = argTypes; + this.failOnArgTypeMismatch = failOnArgTypeMismatch; + } + + @Override + public IScalarEvaluator createScalarEvaluator(IHyracksTaskContext ctx) throws HyracksDataException { + IScalarEvaluator[] argEvals = new IScalarEvaluator[args.length]; + for (int i = 0; i < args.length; i++) { + argEvals[i] = args[i].createScalarEvaluator(ctx); + } + return new RecordConcatEvaluator(argEvals); + } + + private final class RecordConcatEvaluator implements IScalarEvaluator { + + private static final int TABLE_FRAME_SIZE = 32768; + private static final int TABLE_SIZE = 100; + + private final IScalarEvaluator[] argEvals; + private final IPointable[] argPointables; + private final ARecordVisitablePointable[] argRecordPointables; + private final ARecordVisitablePointable openRecordPointable; + + private final BitSet castRequired; + private ACastVisitor castVisitor; + private Triple<IVisitablePointable, IAType, Boolean> castVisitorArg; + + private final RecordBuilder outRecordBuilder; + private final ArrayBackedValueStorage resultStorage; + private final DataOutput resultOutput; + + private final BinaryHashMap fieldMap; + private final BinaryEntry keyEntry; + private final BinaryEntry valEntry; + + private RecordConcatEvaluator(IScalarEvaluator[] argEvals) { + this.argEvals = argEvals; + + argPointables = new IPointable[args.length]; + argRecordPointables = new ARecordVisitablePointable[args.length]; + openRecordPointable = new ARecordVisitablePointable(DefaultOpenFieldType.NESTED_OPEN_RECORD_TYPE); + + resultStorage = new ArrayBackedValueStorage(); + resultOutput = resultStorage.getDataOutput(); + outRecordBuilder = new RecordBuilder(); + outRecordBuilder.reset(openRecordPointable.getInputRecordType()); + + fieldMap = new BinaryHashMap(TABLE_SIZE, TABLE_FRAME_SIZE, outRecordBuilder.getFieldNameHashFunction(), + outRecordBuilder.getFieldNameHashFunction(), outRecordBuilder.getFieldNameComparator()); + keyEntry = new BinaryEntry(); + valEntry = new BinaryEntry(); + valEntry.set(new byte[0], 0, 0); + + castRequired = new BitSet(); + for (int i = 0; i < args.length; i++) { + argPointables[i] = new VoidPointable(); + ARecordType argType = argTypes[i]; + if (argType != null) { + argRecordPointables[i] = new ARecordVisitablePointable(argType); + if (hasDerivedType(argType.getFieldTypes())) { + castRequired.set(i); + if (castVisitor == null) { + castVisitor = new ACastVisitor(); + castVisitorArg = new Triple<>(openRecordPointable, openRecordPointable.getInputRecordType(), + Boolean.FALSE); + } + } + } + } + } + + @Override + public void evaluate(IFrameTupleReference tuple, IPointable result) throws HyracksDataException { + resultStorage.reset(); + if (validateArgs(tuple)) { + processArgs(); + } + result.set(resultStorage); + } + + private boolean validateArgs(IFrameTupleReference tuple) throws HyracksDataException { + if (args.length == 0) { + writeTypeTag(ATypeTag.SERIALIZED_NULL_TYPE_TAG); + return false; + } + boolean returnMissing = false, returnNull = false; + for (int i = 0; i < argEvals.length; i++) { + IPointable argPtr = argPointables[i]; + argEvals[i].evaluate(tuple, argPtr); + + byte[] data = argPtr.getByteArray(); + int offset = argPtr.getStartOffset(); + byte typeTag = data[offset]; + + if (typeTag == ATypeTag.SERIALIZED_MISSING_TYPE_TAG) { + returnMissing = true; + if (!failOnArgTypeMismatch) { + break; + } + } else if (typeTag == ATypeTag.SERIALIZED_NULL_TYPE_TAG) { + returnNull = true; + } else if (typeTag != ATypeTag.SERIALIZED_RECORD_TYPE_TAG) { + if (failOnArgTypeMismatch) { + throw new TypeMismatchException(BuiltinFunctions.RECORD_CONCAT, i, typeTag, + ATypeTag.SERIALIZED_RECORD_TYPE_TAG); + } else { + returnNull = true; + } + } + } + if (returnMissing) { + writeTypeTag(ATypeTag.SERIALIZED_MISSING_TYPE_TAG); + return false; + } + if (returnNull) { + writeTypeTag(ATypeTag.SERIALIZED_NULL_TYPE_TAG); + return false; + } + return true; + } + + private void processArgs() throws HyracksDataException { + outRecordBuilder.init(); + fieldMap.clear(); + for (int i = argEvals.length - 1; i >= 0; i--) { + try { + appendRecord(argPointables[i], argRecordPointables[i], castRequired.get(i)); + } catch (IOException e) { + throw new HyracksDataException(e); + } + } + outRecordBuilder.write(resultOutput, true); + } + + private void appendRecord(IPointable recordPtr, ARecordVisitablePointable argVisitablePointable, + boolean argCastRequired) throws IOException { + + ARecordVisitablePointable recordPointable; + if (argVisitablePointable != null) { + argVisitablePointable.set(recordPtr); + if (argCastRequired) { + argVisitablePointable.accept(castVisitor, castVisitorArg); + recordPointable = openRecordPointable; + } else { + recordPointable = argVisitablePointable; + } + } else { + openRecordPointable.set(recordPtr); + recordPointable = openRecordPointable; + } + + List<IVisitablePointable> fieldNames = recordPointable.getFieldNames(); + List<IVisitablePointable> fieldValues = recordPointable.getFieldValues(); + for (int i = 0, fieldCount = fieldNames.size(); i < fieldCount; i++) { + IVisitablePointable fieldName = fieldNames.get(i); + if (canAppendField(fieldName.getByteArray(), fieldName.getStartOffset() + 1, + fieldName.getLength() - 1)) { + outRecordBuilder.addField(fieldName, fieldValues.get(i)); + } + } + } + + private boolean canAppendField(byte[] buf, int offset, int length) throws HyracksDataException { + keyEntry.set(buf, offset, length); + return fieldMap.put(keyEntry, valEntry) == null; + } + + private boolean hasDerivedType(IAType[] types) { + for (IAType type : types) { + if (type.getTypeTag().isDerivedType()) { + return true; + } + } + return false; + } + + private void writeTypeTag(byte typeTag) throws HyracksDataException { + try { + resultOutput.writeByte(typeTag); + } catch (IOException e) { + throw new HyracksDataException(e); + } + } + } +} http://git-wip-us.apache.org/repos/asf/asterixdb/blob/5cdaa5d6/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/records/RecordConcatStrictDescriptor.java ---------------------------------------------------------------------- diff --git a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/records/RecordConcatStrictDescriptor.java b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/records/RecordConcatStrictDescriptor.java new file mode 100644 index 0000000..77fe301 --- /dev/null +++ b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/records/RecordConcatStrictDescriptor.java @@ -0,0 +1,66 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.asterix.runtime.evaluators.functions.records; + +import org.apache.asterix.om.functions.BuiltinFunctions; +import org.apache.asterix.om.functions.IFunctionDescriptor; +import org.apache.asterix.om.functions.IFunctionDescriptorFactory; +import org.apache.asterix.om.functions.IFunctionTypeInferer; +import org.apache.asterix.om.types.ARecordType; +import org.apache.asterix.runtime.evaluators.base.AbstractScalarFunctionDynamicDescriptor; +import org.apache.asterix.runtime.functions.FunctionTypeInferers; +import org.apache.hyracks.algebricks.core.algebra.functions.FunctionIdentifier; +import org.apache.hyracks.algebricks.runtime.base.IScalarEvaluatorFactory; + +/** + * Concatenates multiple records into one. Fails if an argument is not a record. + */ +public class RecordConcatStrictDescriptor extends AbstractScalarFunctionDynamicDescriptor { + public static final IFunctionDescriptorFactory FACTORY = new IFunctionDescriptorFactory() { + @Override + public IFunctionDescriptor createFunctionDescriptor() { + return new RecordConcatStrictDescriptor(); + } + + @Override + public IFunctionTypeInferer createFunctionTypeInferer() { + return new FunctionTypeInferers.RecordConcatTypeInferer(); + } + }; + + private static final long serialVersionUID = 1L; + + private ARecordType[] argTypes; + + @Override + public void setImmutableStates(Object... states) { + argTypes = (ARecordType[]) states; + } + + @Override + public IScalarEvaluatorFactory createEvaluatorFactory(final IScalarEvaluatorFactory[] args) { + return new RecordConcatEvalFactory(args, argTypes, true); + } + + @Override + public FunctionIdentifier getIdentifier() { + return BuiltinFunctions.RECORD_CONCAT_STRICT; + } +} http://git-wip-us.apache.org/repos/asf/asterixdb/blob/5cdaa5d6/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/functions/FunctionCollection.java ---------------------------------------------------------------------- diff --git a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/functions/FunctionCollection.java b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/functions/FunctionCollection.java index f3eb6c9..a111642 100644 --- a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/functions/FunctionCollection.java +++ b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/functions/FunctionCollection.java @@ -270,6 +270,8 @@ import org.apache.asterix.runtime.evaluators.functions.records.FieldAccessNested import org.apache.asterix.runtime.evaluators.functions.records.GetRecordFieldValueDescriptor; import org.apache.asterix.runtime.evaluators.functions.records.GetRecordFieldsDescriptor; import org.apache.asterix.runtime.evaluators.functions.records.RecordAddFieldsDescriptor; +import org.apache.asterix.runtime.evaluators.functions.records.RecordConcatDescriptor; +import org.apache.asterix.runtime.evaluators.functions.records.RecordConcatStrictDescriptor; import org.apache.asterix.runtime.evaluators.functions.records.RecordMergeDescriptor; import org.apache.asterix.runtime.evaluators.functions.records.RecordPairsDescriptor; import org.apache.asterix.runtime.evaluators.functions.records.RecordRemoveFieldsDescriptor; @@ -424,9 +426,11 @@ public final class FunctionCollection { fc.add(AndDescriptor.FACTORY); fc.add(OrDescriptor.FACTORY); - // Record constructors + // Record constructors / functions fc.add(ClosedRecordConstructorDescriptor.FACTORY); fc.add(OpenRecordConstructorDescriptor.FACTORY); + fc.add(RecordConcatDescriptor.FACTORY); + fc.add(RecordConcatStrictDescriptor.FACTORY); // List constructors fc.add(OrderedListConstructorDescriptor.FACTORY); http://git-wip-us.apache.org/repos/asf/asterixdb/blob/5cdaa5d6/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/functions/FunctionTypeInferers.java ---------------------------------------------------------------------- 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 b8d9778..6261fb3 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 @@ -27,6 +27,7 @@ import org.apache.asterix.om.functions.IFunctionDescriptor; import org.apache.asterix.om.functions.IFunctionTypeInferer; import org.apache.asterix.om.pointables.base.DefaultOpenFieldType; import org.apache.asterix.om.typecomputer.base.TypeCastUtils; +import org.apache.asterix.om.typecomputer.impl.TypeComputeUtils; import org.apache.asterix.om.types.ARecordType; import org.apache.asterix.om.types.ATypeTag; import org.apache.asterix.om.types.AUnionType; @@ -277,4 +278,23 @@ public final class FunctionTypeInferers { fd.setImmutableStates(outType, type0, type1); } } + + public static final class RecordConcatTypeInferer implements IFunctionTypeInferer { + @Override + public void infer(ILogicalExpression expr, IFunctionDescriptor fd, IVariableTypeEnvironment context, + CompilerProperties compilerProps) throws AlgebricksException { + AbstractFunctionCallExpression f = (AbstractFunctionCallExpression) expr; + List<Mutable<ILogicalExpression>> args = f.getArguments(); + int n = args.size(); + ARecordType[] argRecordTypes = new ARecordType[n]; + for (int i = 0; i < n; i++) { + IAType argType = (IAType) context.getType(args.get(i).getValue()); + IAType t = TypeComputeUtils.getActualType(argType); + if (t.getTypeTag() == ATypeTag.OBJECT) { + argRecordTypes[i] = (ARecordType) t; + } + } + fd.setImmutableStates((Object[]) argRecordTypes); + } + } } http://git-wip-us.apache.org/repos/asf/asterixdb/blob/5cdaa5d6/hyracks-fullstack/hyracks/hyracks-util/src/main/java/org/apache/hyracks/util/string/UTF8StringUtil.java ---------------------------------------------------------------------- diff --git a/hyracks-fullstack/hyracks/hyracks-util/src/main/java/org/apache/hyracks/util/string/UTF8StringUtil.java b/hyracks-fullstack/hyracks/hyracks-util/src/main/java/org/apache/hyracks/util/string/UTF8StringUtil.java index 5d69448..11fb6c0 100644 --- a/hyracks-fullstack/hyracks/hyracks-util/src/main/java/org/apache/hyracks/util/string/UTF8StringUtil.java +++ b/hyracks-fullstack/hyracks/hyracks-util/src/main/java/org/apache/hyracks/util/string/UTF8StringUtil.java @@ -35,7 +35,7 @@ import org.apache.hyracks.util.encoding.VarLenIntEncoderDecoder; public class UTF8StringUtil { public static char charAt(byte[] b, int s) { if (s >= b.length) { - throw new ArrayIndexOutOfBoundsException("Are you crazy?"); + throw new ArrayIndexOutOfBoundsException(s); } int c = b[s] & 0xff; switch (c >> 4) {