Till Westmann has submitted this change and it was merged. Change subject: [ASTERIXDB-2417][COMP] Fix issues with LIMIT clause ......................................................................
[ASTERIXDB-2417][COMP] Fix issues with LIMIT clause - user model changes: yes - storage format changes: no - interface changes: no Details: - Fixed NPE in optimizer when limit/offset is non-integer - Allow float/double values that are integers in limit/offset - Make consistent limit/offset value types (integer) between runtime and optimizer rules - Add internal function treat-as-integer() that returns integer if input number conforms to the integer type or fails otherwise Change-Id: I986fab3e79b072aa2441af293f3e16c3f37bf508 Reviewed-on: https://asterix-gerrit.ics.uci.edu/2788 Tested-by: Jenkins <jenk...@fulliautomatix.ics.uci.edu> Contrib: Jenkins <jenk...@fulliautomatix.ics.uci.edu> Integration-Tests: Jenkins <jenk...@fulliautomatix.ics.uci.edu> Reviewed-by: Till Westmann <ti...@apache.org> --- M asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/base/RuleCollections.java M asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/PushLimitIntoOrderByRule.java M asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/PushLimitIntoPrimarySearchRule.java M asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/LangExpressionToPlanTranslator.java A asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/limit/limit_type_01/limit_type_01.1.query.sqlpp A asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/limit/limit_type_02/limit_type_02.1.query.sqlpp A asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/limit/limit_type_02/limit_type_02.2.query.sqlpp A asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/limit/limit_type_02/limit_type_02.3.query.sqlpp A asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/limit/limit_type_02/limit_type_02.4.query.sqlpp A asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/limit/limit_type_02/limit_type_02.5.query.sqlpp A asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/limit/limit_type_02/limit_type_02.6.query.sqlpp A asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/limit/push-limit-to-primary-lookup/push-limit-to-primary-lookup.5.query.sqlpp A asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/limit/push-limit-to-primary-scan/push-limit-to-primary-scan.5.query.sqlpp A asterixdb/asterix-app/src/test/resources/runtimets/results/limit/limit_type_01/limit_type_01.1.adm A asterixdb/asterix-app/src/test/resources/runtimets/results/limit/push-limit-to-primary-lookup/push-limit-to-primary-lookup.5.adm A asterixdb/asterix-app/src/test/resources/runtimets/results/limit/push-limit-to-primary-scan/push-limit-to-primary-scan.5.adm M asterixdb/asterix-app/src/test/resources/runtimets/testsuite_sqlpp.xml M asterixdb/asterix-common/src/main/java/org/apache/asterix/common/exceptions/ErrorCode.java M asterixdb/asterix-common/src/main/resources/asx_errormsg/en.properties M asterixdb/asterix-om/src/main/java/org/apache/asterix/om/functions/BuiltinFunctions.java A asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/TreatAsTypeComputer.java A asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/TreatAsIntegerDescriptor.java M asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/functions/FunctionCollection.java 23 files changed, 613 insertions(+), 117 deletions(-) Approvals: Till Westmann: Looks good to me, approved Jenkins: Verified; ; Verified Objections: Anon. E. Moose #1000171: Violations found Jenkins: Violations found diff --git a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/base/RuleCollections.java b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/base/RuleCollections.java index 134c96f..85d1c29 100644 --- a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/base/RuleCollections.java +++ b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/base/RuleCollections.java @@ -182,13 +182,14 @@ normalization.add(new IntroduceDynamicTypeCastRule()); normalization.add(new IntroduceDynamicTypeCastForExternalFunctionRule()); normalization.add(new IntroduceEnforcedListTypeRule()); + // Perform constant folding before common expression extraction + normalization.add(new ConstantFoldingRule(appCtx)); normalization.add(new ExtractCommonExpressionsRule()); // Let PushAggFuncIntoStandaloneAggregateRule run after ExtractCommonExpressionsRule // so that PushAggFunc can happen in fewer places. normalization.add(new PushAggFuncIntoStandaloneAggregateRule()); normalization.add(new ListifyUnnestingFunctionRule()); - normalization.add(new ConstantFoldingRule(appCtx)); normalization.add(new RemoveRedundantSelectRule()); normalization.add(new UnnestToDataScanRule()); normalization.add(new MetaFunctionToMetaVariableRule()); diff --git a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/PushLimitIntoOrderByRule.java b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/PushLimitIntoOrderByRule.java index 56dc675..e64889d 100644 --- a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/PushLimitIntoOrderByRule.java +++ b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/PushLimitIntoOrderByRule.java @@ -18,12 +18,15 @@ */ package org.apache.asterix.optimizer.rules; -import org.apache.asterix.optimizer.rules.am.AccessMethodUtils; +import org.apache.asterix.om.base.AInt32; +import org.apache.asterix.om.base.IAObject; +import org.apache.asterix.om.types.ATypeTag; +import org.apache.asterix.om.utils.ConstantExpressionUtil; import org.apache.commons.lang3.mutable.Mutable; import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException; +import org.apache.hyracks.algebricks.core.algebra.base.ILogicalExpression; import org.apache.hyracks.algebricks.core.algebra.base.ILogicalOperator; import org.apache.hyracks.algebricks.core.algebra.base.IOptimizationContext; -import org.apache.hyracks.algebricks.core.algebra.base.LogicalExpressionTag; import org.apache.hyracks.algebricks.core.algebra.base.LogicalOperatorTag; import org.apache.hyracks.algebricks.core.algebra.base.PhysicalOperatorTag; import org.apache.hyracks.algebricks.core.algebra.operators.logical.AbstractLogicalOperator; @@ -89,50 +92,19 @@ PhysicalOptimizationConfig physicalOptimizationConfig = context.getPhysicalOptimizationConfig(); LimitOperator limitOp = (LimitOperator) opRef.getValue(); OrderOperator orderOp = (OrderOperator) opRef2.getValue(); - long topK = -1; // We don't push-down LIMIT into in-memory sort. if (orderOp.getPhysicalOperator().getOperatorTag() != PhysicalOperatorTag.STABLE_SORT) { return false; } - // Get the LIMIT constant - if (limitOp.getMaxObjects().getValue().getExpressionTag() == LogicalExpressionTag.CONSTANT) { - // Currently, we support LIMIT with a constant value. - topK = AccessMethodUtils.getInt64Constant(limitOp.getMaxObjects()); - // If topK is huge, there is no reason to use topK sort module - // since the original external sort's performance might be better. - if (topK > Integer.MAX_VALUE) { - return false; - } - if (topK < 0) { - topK = 0; - } - } else { + Integer topK = getOutputLimit(limitOp); + if (topK == null) { return false; } - // Get the offset constant if there is one. If one presents, then topK = topK + offset. - // This is because we can't apply offset to the external sort. - // Final topK will be applied through LIMIT. - if (limitOp.getOffset().getValue() != null) { - if (limitOp.getOffset().getValue().getExpressionTag() == LogicalExpressionTag.CONSTANT) { - long offset = AccessMethodUtils.getInt64Constant(limitOp.getOffset()); - if (offset < 0) { - offset = 0; - } - // Check the overflow case. - if (offset >= Integer.MAX_VALUE - topK) { - return false; - } - topK += offset; - } else { - return false; - } - } - // Create the new ORDER operator, set the topK value, and replace the current one. - OrderOperator newOrderOp = new OrderOperator(orderOp.getOrderExpressions(), (int) topK); + OrderOperator newOrderOp = new OrderOperator(orderOp.getOrderExpressions(), topK); newOrderOp.setSourceLocation(orderOp.getSourceLocation()); newOrderOp.setPhysicalOperator( new StableSortPOperator(physicalOptimizationConfig.getMaxFramesExternalSort(), newOrderOp.getTopK())); @@ -146,4 +118,38 @@ return true; } + static Integer getOutputLimit(LimitOperator limitOp) { + // Currently, we support LIMIT with a constant value. + ILogicalExpression maxObjectsExpr = limitOp.getMaxObjects().getValue(); + IAObject maxObjectsValue = ConstantExpressionUtil.getConstantIaObject(maxObjectsExpr, ATypeTag.INTEGER); + if (maxObjectsValue == null) { + return null; + } + int topK = ((AInt32) maxObjectsValue).getIntegerValue(); + if (topK < 0) { + topK = 0; + } + + // Get the offset constant if there is one. If one presents, then topK = topK + offset. + // This is because we can't apply offset to the external sort. + // Final topK will be applied through LIMIT. + ILogicalExpression offsetExpr = limitOp.getOffset().getValue(); + if (offsetExpr != null) { + IAObject offsetValue = ConstantExpressionUtil.getConstantIaObject(offsetExpr, ATypeTag.INTEGER); + if (offsetValue == null) { + return null; + } + int offset = ((AInt32) offsetValue).getIntegerValue(); + if (offset < 0) { + offset = 0; + } + // Check the overflow case. + if (offset >= Integer.MAX_VALUE - topK) { + return null; + } + topK += offset; + } + + return topK; + } } diff --git a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/PushLimitIntoPrimarySearchRule.java b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/PushLimitIntoPrimarySearchRule.java index 921d231..5427ca6 100644 --- a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/PushLimitIntoPrimarySearchRule.java +++ b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/PushLimitIntoPrimarySearchRule.java @@ -25,7 +25,6 @@ import org.apache.asterix.metadata.declared.DataSource; import org.apache.asterix.om.functions.BuiltinFunctions; import org.apache.asterix.optimizer.rules.am.AccessMethodJobGenParams; -import org.apache.asterix.optimizer.rules.am.AccessMethodUtils; import org.apache.commons.lang3.mutable.Mutable; import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException; import org.apache.hyracks.algebricks.core.algebra.base.ILogicalExpression; @@ -67,7 +66,7 @@ } context.addToDontApplySet(this, op); - Long outputLimit = getOutputLimit((LimitOperator) op); + Integer outputLimit = PushLimitIntoOrderByRule.getOutputLimit((LimitOperator) op); if (outputLimit == null) { // we cannot push if limit is not constant return false; @@ -77,7 +76,7 @@ if (childOp.getValue().getOperatorTag() == LogicalOperatorTag.EXCHANGE) { childOp = childOp.getValue().getInputs().get(0); } - boolean changed = false; + boolean changed; if (childOp.getValue().getOperatorTag() == LogicalOperatorTag.SELECT) { changed = rewriteSelect(childOp, outputLimit); } else { @@ -89,21 +88,7 @@ return changed; } - private Long getOutputLimit(LimitOperator limit) { - if (limit.getMaxObjects().getValue().getExpressionTag() != LogicalExpressionTag.CONSTANT) { - return null; - } - long outputLimit = AccessMethodUtils.getInt64Constant(limit.getMaxObjects()); - if (limit.getOffset() != null && limit.getOffset().getValue() != null) { - if (limit.getOffset().getValue().getExpressionTag() != LogicalExpressionTag.CONSTANT) { - return null; - } - outputLimit += AccessMethodUtils.getInt64Constant(limit.getOffset()); - } - return outputLimit; - } - - private boolean rewriteSelect(Mutable<ILogicalOperator> op, long outputLimit) throws AlgebricksException { + private boolean rewriteSelect(Mutable<ILogicalOperator> op, int outputLimit) { SelectOperator select = (SelectOperator) op.getValue(); Set<LogicalVariable> selectedVariables = new HashSet<>(); select.getCondition().getValue().getUsedVariables(selectedVariables); @@ -131,7 +116,7 @@ return changed; } - private boolean setLimitForScanOrUnnestMap(ILogicalOperator op, long outputLimit) throws AlgebricksException { + private boolean setLimitForScanOrUnnestMap(ILogicalOperator op, int outputLimit) { if (op.getOperatorTag() == LogicalOperatorTag.DATASOURCESCAN) { DataSourceScanOperator scan = (DataSourceScanOperator) op; if (isScanPushable(scan, Collections.emptySet())) { diff --git a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/LangExpressionToPlanTranslator.java b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/LangExpressionToPlanTranslator.java index 18a6597..5410a94 100644 --- a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/LangExpressionToPlanTranslator.java +++ b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/LangExpressionToPlanTranslator.java @@ -1085,38 +1085,27 @@ ILogicalExpression e = p.first; // now look at the operator if (i < nOps) { - if (OperatorExpr.opIsComparison(ops.get(i))) { - AbstractFunctionCallExpression c = createComparisonExpression(ops.get(i), sourceLoc); + OperatorType opType = ops.get(i); + boolean isCmpOp = OperatorExpr.opIsComparison(opType); + AbstractFunctionCallExpression f = createFunctionCallExpressionForBuiltinOperator(opType, sourceLoc); - // chain the operators - if (i == 0) { - c.getArguments().add(new MutableObject<>(e)); - currExpr = c; - if (op.isBroadcastOperand(i)) { - BroadcastExpressionAnnotation bcast = new BroadcastExpressionAnnotation(); - bcast.setObject(BroadcastSide.LEFT); - c.getAnnotations().put(BroadcastExpressionAnnotation.BROADCAST_ANNOTATION_KEY, bcast); - } - } else { - currExpr.getArguments().add(new MutableObject<>(e)); - c.getArguments().add(new MutableObject<>(currExpr)); - currExpr = c; - if (i == 1 && op.isBroadcastOperand(i)) { - BroadcastExpressionAnnotation bcast = new BroadcastExpressionAnnotation(); - bcast.setObject(BroadcastSide.RIGHT); - c.getAnnotations().put(BroadcastExpressionAnnotation.BROADCAST_ANNOTATION_KEY, bcast); - } + // chain the operators + if (i == 0) { + f.getArguments().add(new MutableObject<>(e)); + currExpr = f; + if (isCmpOp && op.isBroadcastOperand(i)) { + BroadcastExpressionAnnotation bcast = new BroadcastExpressionAnnotation(); + bcast.setObject(BroadcastSide.LEFT); + f.getAnnotations().put(BroadcastExpressionAnnotation.BROADCAST_ANNOTATION_KEY, bcast); } } else { - AbstractFunctionCallExpression f = - createFunctionCallExpressionForBuiltinOperator(ops.get(i), sourceLoc); - if (i == 0) { - f.getArguments().add(new MutableObject<>(e)); - currExpr = f; - } else { - currExpr.getArguments().add(new MutableObject<>(e)); - f.getArguments().add(new MutableObject<>(currExpr)); - currExpr = f; + currExpr.getArguments().add(new MutableObject<>(e)); + f.getArguments().add(new MutableObject<>(currExpr)); + currExpr = f; + if (isCmpOp && i == 1 && op.isBroadcastOperand(i)) { + BroadcastExpressionAnnotation bcast = new BroadcastExpressionAnnotation(); + bcast.setObject(BroadcastSide.RIGHT); + f.getAnnotations().put(BroadcastExpressionAnnotation.BROADCAST_ANNOTATION_KEY, bcast); } } } else { // don't forget the last expression... @@ -1359,53 +1348,52 @@ public Pair<ILogicalOperator, LogicalVariable> visit(LimitClause lc, Mutable<ILogicalOperator> tupSource) throws CompilationException { SourceLocation sourceLoc = lc.getSourceLocation(); - Pair<ILogicalExpression, Mutable<ILogicalOperator>> p1 = langExprToAlgExpression(lc.getLimitExpr(), tupSource); LimitOperator opLim; + + Pair<ILogicalExpression, Mutable<ILogicalOperator>> p1 = langExprToAlgExpression(lc.getLimitExpr(), tupSource); + AbstractFunctionCallExpression maxObjectsExpr = + createFunctionCallExpression(BuiltinFunctions.TREAT_AS_INTEGER, lc.getLimitExpr().getSourceLocation()); + maxObjectsExpr.getArguments().add(new MutableObject<>(p1.first)); + Expression offset = lc.getOffset(); if (offset != null) { Pair<ILogicalExpression, Mutable<ILogicalOperator>> p2 = langExprToAlgExpression(offset, p1.second); - opLim = new LimitOperator(p1.first, p2.first); + AbstractFunctionCallExpression offsetExpr = + createFunctionCallExpression(BuiltinFunctions.TREAT_AS_INTEGER, lc.getOffset().getSourceLocation()); + offsetExpr.getArguments().add(new MutableObject<>(p2.first)); + opLim = new LimitOperator(maxObjectsExpr, offsetExpr); opLim.getInputs().add(p2.second); opLim.setSourceLocation(sourceLoc); } else { - opLim = new LimitOperator(p1.first); + opLim = new LimitOperator(maxObjectsExpr); opLim.getInputs().add(p1.second); opLim.setSourceLocation(sourceLoc); } return new Pair<>(opLim, null); } - protected AbstractFunctionCallExpression createComparisonExpression(OperatorType t, SourceLocation sourceLoc) { - FunctionIdentifier fi = operatorTypeToFunctionIdentifier(t); - IFunctionInfo finfo = FunctionUtil.getFunctionInfo(fi); - ScalarFunctionCallExpression callExpr = new ScalarFunctionCallExpression(finfo); - callExpr.setSourceLocation(sourceLoc); - return callExpr; - } - - private static FunctionIdentifier operatorTypeToFunctionIdentifier(OperatorType t) { - switch (t) { - case EQ: - return AlgebricksBuiltinFunctions.EQ; - case NEQ: - return AlgebricksBuiltinFunctions.NEQ; - case GT: - return AlgebricksBuiltinFunctions.GT; - case GE: - return AlgebricksBuiltinFunctions.GE; - case LT: - return AlgebricksBuiltinFunctions.LT; - case LE: - return AlgebricksBuiltinFunctions.LE; - default: - throw new IllegalStateException(); - } - } - - protected AbstractFunctionCallExpression createFunctionCallExpressionForBuiltinOperator(OperatorType t, + private static AbstractFunctionCallExpression createFunctionCallExpressionForBuiltinOperator(OperatorType t, SourceLocation sourceLoc) throws CompilationException { FunctionIdentifier fid; switch (t) { + case EQ: + fid = AlgebricksBuiltinFunctions.EQ; + break; + case NEQ: + fid = AlgebricksBuiltinFunctions.NEQ; + break; + case GT: + fid = AlgebricksBuiltinFunctions.GT; + break; + case GE: + fid = AlgebricksBuiltinFunctions.GE; + break; + case LT: + fid = AlgebricksBuiltinFunctions.LT; + break; + case LE: + fid = AlgebricksBuiltinFunctions.LE; + break; case PLUS: fid = AlgebricksBuiltinFunctions.NUMERIC_ADD; break; @@ -1440,6 +1428,11 @@ throw new CompilationException(ErrorCode.COMPILATION_ERROR, sourceLoc, "Operator " + t + " is not yet implemented"); } + return createFunctionCallExpression(fid, sourceLoc); + } + + private static AbstractFunctionCallExpression createFunctionCallExpression(FunctionIdentifier fid, + SourceLocation sourceLoc) { ScalarFunctionCallExpression callExpr = new ScalarFunctionCallExpression(FunctionUtil.getFunctionInfo(fid)); callExpr.setSourceLocation(sourceLoc); return callExpr; diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/limit/limit_type_01/limit_type_01.1.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/limit/limit_type_01/limit_type_01.1.query.sqlpp new file mode 100644 index 0000000..c8b2b7a --- /dev/null +++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/limit/limit_type_01/limit_type_01.1.query.sqlpp @@ -0,0 +1,29 @@ +/* + * 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. + */ + +/* + * Description : Test expressions returning floating point numbers + * : in limit/offset + * Expected Result : Success + */ + +select value t +from [6,5,4,3,2,1] t +order by t +limit 7.5/2.5 offset 5/2.5 \ No newline at end of file diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/limit/limit_type_02/limit_type_02.1.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/limit/limit_type_02/limit_type_02.1.query.sqlpp new file mode 100644 index 0000000..ce55ac9 --- /dev/null +++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/limit/limit_type_02/limit_type_02.1.query.sqlpp @@ -0,0 +1,28 @@ +/* + * 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. + */ + +/* + * Description : Test floating point type in limit/offset + * Expected Result : Failure + */ + +select value t +from [6,5,4,3,2,1] t +order by t +limit 5.5/2 \ No newline at end of file diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/limit/limit_type_02/limit_type_02.2.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/limit/limit_type_02/limit_type_02.2.query.sqlpp new file mode 100644 index 0000000..e479296 --- /dev/null +++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/limit/limit_type_02/limit_type_02.2.query.sqlpp @@ -0,0 +1,28 @@ +/* + * 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. + */ + +/* + * Description : Test floating point type in limit/offset + * Expected Result : Failure + */ + +select value t +from [6,5,4,3,2,1] t +order by t +limit 1 offset 3.5/2 \ No newline at end of file diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/limit/limit_type_02/limit_type_02.3.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/limit/limit_type_02/limit_type_02.3.query.sqlpp new file mode 100644 index 0000000..b870b76 --- /dev/null +++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/limit/limit_type_02/limit_type_02.3.query.sqlpp @@ -0,0 +1,28 @@ +/* + * 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. + */ + +/* + * Description : Test floating point type in limit/offset + * Expected Result : Failure + */ + +select value t +from [6,5,4,3,2,1] t +order by t +limit "2" \ No newline at end of file diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/limit/limit_type_02/limit_type_02.4.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/limit/limit_type_02/limit_type_02.4.query.sqlpp new file mode 100644 index 0000000..3e3bfa7 --- /dev/null +++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/limit/limit_type_02/limit_type_02.4.query.sqlpp @@ -0,0 +1,28 @@ +/* + * 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. + */ + +/* + * Description : Test floating point type in limit/offset + * Expected Result : Failure + */ + +select value t +from [6,5,4,3,2,1] t +order by t +limit 2 offset true \ No newline at end of file diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/limit/limit_type_02/limit_type_02.5.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/limit/limit_type_02/limit_type_02.5.query.sqlpp new file mode 100644 index 0000000..d783bb1 --- /dev/null +++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/limit/limit_type_02/limit_type_02.5.query.sqlpp @@ -0,0 +1,28 @@ +/* + * 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. + */ + +/* + * Description : Test overflow error in limit/offset + * Expected Result : Failure + */ + +select value t +from [6,5,4,3,2,1] t +order by t +limit 9999999999 \ No newline at end of file diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/limit/limit_type_02/limit_type_02.6.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/limit/limit_type_02/limit_type_02.6.query.sqlpp new file mode 100644 index 0000000..991f189 --- /dev/null +++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/limit/limit_type_02/limit_type_02.6.query.sqlpp @@ -0,0 +1,28 @@ +/* + * 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. + */ + +/* + * Description : Test overflow error in limit/offset + * Expected Result : Failure + */ + +select value t +from [6,5,4,3,2,1] t +order by t +limit 1 offset 8888888888 \ No newline at end of file diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/limit/push-limit-to-primary-lookup/push-limit-to-primary-lookup.5.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/limit/push-limit-to-primary-lookup/push-limit-to-primary-lookup.5.query.sqlpp new file mode 100644 index 0000000..5673992 --- /dev/null +++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/limit/push-limit-to-primary-lookup/push-limit-to-primary-lookup.5.query.sqlpp @@ -0,0 +1,25 @@ +/* + * 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. + */ + +use test; + +explain select element c +from LineItem as c +where (c.l_suppkey < 150) +limit 7.5/1.5 offset 7.5/1.5; diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/limit/push-limit-to-primary-scan/push-limit-to-primary-scan.5.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/limit/push-limit-to-primary-scan/push-limit-to-primary-scan.5.query.sqlpp new file mode 100644 index 0000000..fc9d42f --- /dev/null +++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/limit/push-limit-to-primary-scan/push-limit-to-primary-scan.5.query.sqlpp @@ -0,0 +1,26 @@ +/* + * 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. + */ +/* scan and print a delimited text file */ + +use test; + +explain + select element paper + from DBLP1 as paper + limit 7.5/1.5 offset 7.5/1.5; diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/limit/limit_type_01/limit_type_01.1.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/limit/limit_type_01/limit_type_01.1.adm new file mode 100644 index 0000000..af64121 --- /dev/null +++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/limit/limit_type_01/limit_type_01.1.adm @@ -0,0 +1,3 @@ +3 +4 +5 \ No newline at end of file diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/limit/push-limit-to-primary-lookup/push-limit-to-primary-lookup.5.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/limit/push-limit-to-primary-lookup/push-limit-to-primary-lookup.5.adm new file mode 100644 index 0000000..d070b2b --- /dev/null +++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/limit/push-limit-to-primary-lookup/push-limit-to-primary-lookup.5.adm @@ -0,0 +1,34 @@ +distribute result [$$c] +-- DISTRIBUTE_RESULT |UNPARTITIONED| + exchange + -- ONE_TO_ONE_EXCHANGE |UNPARTITIONED| + limit 5, 5 + -- STREAM_LIMIT |UNPARTITIONED| + project ([$$c]) + -- STREAM_PROJECT |PARTITIONED| + exchange + -- SORT_MERGE_EXCHANGE [$$14(ASC), $$15(ASC) ] |PARTITIONED| + limit 10 + -- STREAM_LIMIT |PARTITIONED| + exchange + -- ONE_TO_ONE_EXCHANGE |PARTITIONED| + unnest-map [$$14, $$15, $$c] <- index-search("LineItem", 0, "test", "LineItem", FALSE, FALSE, 2, $$19, $$20, 2, $$19, $$20, TRUE, TRUE, TRUE) condition (lt($$c.getField(2), 150)) limit 10 + -- BTREE_SEARCH |PARTITIONED| + exchange + -- ONE_TO_ONE_EXCHANGE |PARTITIONED| + order (ASC, $$19) (ASC, $$20) + -- STABLE_SORT [$$19(ASC), $$20(ASC)] |PARTITIONED| + exchange + -- ONE_TO_ONE_EXCHANGE |PARTITIONED| + project ([$$19, $$20]) + -- STREAM_PROJECT |PARTITIONED| + exchange + -- ONE_TO_ONE_EXCHANGE |PARTITIONED| + unnest-map [$$18, $$19, $$20] <- index-search("idx_LineItem_suppkey", 0, "test", "LineItem", FALSE, FALSE, 0, 1, $$17, TRUE, FALSE, FALSE) + -- BTREE_SEARCH |PARTITIONED| + exchange + -- ONE_TO_ONE_EXCHANGE |PARTITIONED| + assign [$$17] <- [150] + -- ASSIGN |PARTITIONED| + empty-tuple-source + -- EMPTY_TUPLE_SOURCE |PARTITIONED| diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/limit/push-limit-to-primary-scan/push-limit-to-primary-scan.5.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/limit/push-limit-to-primary-scan/push-limit-to-primary-scan.5.adm new file mode 100644 index 0000000..ee3e565 --- /dev/null +++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/limit/push-limit-to-primary-scan/push-limit-to-primary-scan.5.adm @@ -0,0 +1,20 @@ +distribute result [$$paper] +-- DISTRIBUTE_RESULT |UNPARTITIONED| + exchange + -- ONE_TO_ONE_EXCHANGE |UNPARTITIONED| + limit 5, 5 + -- STREAM_LIMIT |UNPARTITIONED| + project ([$$paper]) + -- STREAM_PROJECT |PARTITIONED| + exchange + -- SORT_MERGE_EXCHANGE [$$12(ASC) ] |PARTITIONED| + limit 10 + -- STREAM_LIMIT |PARTITIONED| + exchange + -- ONE_TO_ONE_EXCHANGE |PARTITIONED| + data-scan []<-[$$12, $$paper] <- test.DBLP1 limit 10 + -- DATASOURCE_SCAN |PARTITIONED| + exchange + -- ONE_TO_ONE_EXCHANGE |PARTITIONED| + empty-tuple-source + -- EMPTY_TUPLE_SOURCE |PARTITIONED| diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_sqlpp.xml b/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_sqlpp.xml index 2adba01..c5775d8 100644 --- a/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_sqlpp.xml +++ b/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_sqlpp.xml @@ -10156,11 +10156,28 @@ </test-group> <test-group name="limit"> <test-case FilePath="limit"> + <compilation-unit name="limit_type_01"> + <output-dir compare="Text">limit_type_01</output-dir> + </compilation-unit> + </test-case> + <test-case FilePath="limit"> + <compilation-unit name="limit_type_02"> + <output-dir compare="Text">limit_type_01</output-dir> + <expected-error>ASX0039: Expected integer value, got 2.75 (in line 28, at column 10)</expected-error> + <expected-error>ASX0039: Expected integer value, got 1.75 (in line 28, at column 19)</expected-error> + <expected-error>ASX1091: Type mismatch: expected value of type integer, but got the value of type string (in line 28, at column 7)</expected-error> + <expected-error>ASX1091: Type mismatch: expected value of type integer, but got the value of type boolean (in line 28, at column 16)</expected-error> + <expected-error>ASX0021: Source value 9999999999 is out of range that integer can hold - integer.MAX_VALUE: 2147483647, integer.MIN_VALUE: -2147483648</expected-error> + <expected-error>ASX0021: Source value 8888888888 is out of range that integer can hold - integer.MAX_VALUE: 2147483647, integer.MIN_VALUE: -2147483648</expected-error> + <source-location>false</source-location> + </compilation-unit> + </test-case> + <test-case FilePath="limit"> <compilation-unit name="push-limit-to-primary-scan"> <output-dir compare="Text">push-limit-to-primary-scan</output-dir> </compilation-unit> </test-case> - <test-case FilePath="limit"> + <test-case FilePath="limit"> <compilation-unit name="push-limit-to-primary-scan-select"> <output-dir compare="Text">push-limit-to-primary-scan-select</output-dir> </compilation-unit> diff --git a/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/exceptions/ErrorCode.java b/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/exceptions/ErrorCode.java index 2fdbe1e..f570aa8 100644 --- a/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/exceptions/ErrorCode.java +++ b/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/exceptions/ErrorCode.java @@ -79,6 +79,7 @@ public static final int CANNOT_COMPARE_COMPLEX = 36; public static final int TYPE_MISMATCH_GENERIC = 37; public static final int DIFFERENT_LIST_TYPE_ARGS = 38; + public static final int INTEGER_VALUE_EXPECTED = 39; public static final int UNSUPPORTED_JRE = 100; diff --git a/asterixdb/asterix-common/src/main/resources/asx_errormsg/en.properties b/asterixdb/asterix-common/src/main/resources/asx_errormsg/en.properties index ec18324..8c09d75 100644 --- a/asterixdb/asterix-common/src/main/resources/asx_errormsg/en.properties +++ b/asterixdb/asterix-common/src/main/resources/asx_errormsg/en.properties @@ -73,6 +73,7 @@ 35 = Unsupported multiple statements. 36 = Cannot compare non-primitive values 38 = Input contains different list types +39 = Expected integer value, got %1$s 100 = Unsupported JRE: %1$s 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 c7441d6..8f24864 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 @@ -121,6 +121,7 @@ import org.apache.asterix.om.typecomputer.impl.ToDoubleTypeComputer; import org.apache.asterix.om.typecomputer.impl.ToNumberTypeComputer; import org.apache.asterix.om.typecomputer.impl.ToObjectTypeComputer; +import org.apache.asterix.om.typecomputer.impl.TreatAsTypeComputer; import org.apache.asterix.om.typecomputer.impl.UnaryBinaryInt64TypeComputer; import org.apache.asterix.om.typecomputer.impl.UnaryMinusTypeComputer; import org.apache.asterix.om.typecomputer.impl.UnaryStringInt64TypeComputer; @@ -1102,6 +1103,9 @@ public static final FunctionIdentifier TO_STRING = new FunctionIdentifier(FunctionConstants.ASTERIX_NS, "to-string", 1); + public static final FunctionIdentifier TREAT_AS_INTEGER = + new FunctionIdentifier(FunctionConstants.ASTERIX_NS, "treat-as-integer", 1); + public static final FunctionIdentifier EXTERNAL_LOOKUP = new FunctionIdentifier(FunctionConstants.ASTERIX_NS, "external-lookup", FunctionIdentifier.VARARGS); @@ -1297,6 +1301,8 @@ addFunction(TO_OBJECT, ToObjectTypeComputer.INSTANCE, true); addFunction(TO_STRING, AStringTypeComputer.INSTANCE, true); + addPrivateFunction(TREAT_AS_INTEGER, TreatAsTypeComputer.INSTANCE_INTEGER, true); + addFunction(IF_INF, IfNanOrInfTypeComputer.INSTANCE, true); addFunction(IF_MISSING, IfMissingTypeComputer.INSTANCE, true); addFunction(IF_MISSING_OR_NULL, IfMissingOrNullTypeComputer.INSTANCE, true); diff --git a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/TreatAsTypeComputer.java b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/TreatAsTypeComputer.java new file mode 100644 index 0000000..1a5861b --- /dev/null +++ b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/TreatAsTypeComputer.java @@ -0,0 +1,48 @@ +/* + * 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.om.typecomputer.impl; + +import org.apache.asterix.om.exceptions.TypeMismatchException; +import org.apache.asterix.om.typecomputer.base.AbstractResultTypeComputer; +import org.apache.asterix.om.types.BuiltinType; +import org.apache.asterix.om.types.IAType; +import org.apache.asterix.om.types.hierachy.ATypeHierarchy; +import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException; +import org.apache.hyracks.algebricks.core.algebra.base.ILogicalExpression; + +public class TreatAsTypeComputer extends AbstractResultTypeComputer { + public static final TreatAsTypeComputer INSTANCE_INTEGER = new TreatAsTypeComputer(BuiltinType.AINT32); + + private final IAType type; + + private TreatAsTypeComputer(IAType type) { + this.type = type; + } + + @Override + protected IAType getResultType(ILogicalExpression expr, IAType... strippedInputTypes) throws AlgebricksException { + IAType inputType = strippedInputTypes[0]; + if (ATypeHierarchy.isCompatible(inputType.getTypeTag(), type.getTypeTag())) { + return type; + } else { + throw new TypeMismatchException(expr.getSourceLocation(), inputType.getTypeTag(), type.getTypeTag()); + } + } +} diff --git a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/TreatAsIntegerDescriptor.java b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/TreatAsIntegerDescriptor.java new file mode 100644 index 0000000..2c3e148 --- /dev/null +++ b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/TreatAsIntegerDescriptor.java @@ -0,0 +1,130 @@ +/* + * 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; + +import java.io.DataOutput; + +import org.apache.asterix.common.exceptions.ErrorCode; +import org.apache.asterix.common.exceptions.RuntimeDataException; +import org.apache.asterix.formats.nontagged.SerializerDeserializerProvider; +import org.apache.asterix.om.base.AInt32; +import org.apache.asterix.om.base.AMutableInt32; +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.types.ATypeTag; +import org.apache.asterix.om.types.BuiltinType; +import org.apache.asterix.om.types.hierachy.ATypeHierarchy; +import org.apache.asterix.runtime.evaluators.base.AbstractScalarFunctionDynamicDescriptor; +import org.apache.asterix.runtime.exceptions.TypeMismatchException; +import org.apache.hyracks.algebricks.core.algebra.functions.FunctionIdentifier; +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.dataflow.value.ISerializerDeserializer; +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.dataflow.common.data.accessors.IFrameTupleReference; + +public class TreatAsIntegerDescriptor extends AbstractScalarFunctionDynamicDescriptor { + private static final long serialVersionUID = 1L; + public static final IFunctionDescriptorFactory FACTORY = new IFunctionDescriptorFactory() { + @Override + public IFunctionDescriptor createFunctionDescriptor() { + return new TreatAsIntegerDescriptor(); + } + }; + + @Override + public IScalarEvaluatorFactory createEvaluatorFactory(final IScalarEvaluatorFactory[] args) { + return new IScalarEvaluatorFactory() { + private static final long serialVersionUID = 1L; + + @Override + public IScalarEvaluator createScalarEvaluator(final IHyracksTaskContext ctx) throws HyracksDataException { + + final IScalarEvaluator inputEval = args[0].createScalarEvaluator(ctx); + final IPointable inputArg = new VoidPointable(); + final ArrayBackedValueStorage resultStorage = new ArrayBackedValueStorage(); + final DataOutput out = resultStorage.getDataOutput(); + final AMutableInt32 aInt32 = new AMutableInt32(0); + + @SuppressWarnings("unchecked") + final ISerializerDeserializer<AInt32> int32Ser = + SerializerDeserializerProvider.INSTANCE.getSerializerDeserializer(BuiltinType.AINT32); + + return new IScalarEvaluator() { + @Override + public void evaluate(IFrameTupleReference tuple, IPointable result) throws HyracksDataException { + inputEval.evaluate(tuple, inputArg); + + int intValue; + byte[] bytes = inputArg.getByteArray(); + int startOffset = inputArg.getStartOffset(); + ATypeTag tt = ATypeTag.VALUE_TYPE_MAPPING[bytes[startOffset]]; + switch (tt) { + case TINYINT: + case SMALLINT: + case INTEGER: + case BIGINT: + intValue = ATypeHierarchy.getIntegerValue(getIdentifier().getName(), 0, bytes, + startOffset, true); + break; + case FLOAT: + case DOUBLE: + double doubleValue = + ATypeHierarchy.getDoubleValue(getIdentifier().getName(), 0, bytes, startOffset); + intValue = asInt(doubleValue); + break; + default: + throw new TypeMismatchException(sourceLoc, bytes[startOffset], + ATypeTag.SERIALIZED_INT8_TYPE_TAG, ATypeTag.SERIALIZED_INT16_TYPE_TAG, + ATypeTag.SERIALIZED_INT32_TYPE_TAG, ATypeTag.SERIALIZED_INT64_TYPE_TAG, + ATypeTag.SERIALIZED_FLOAT_TYPE_TAG, ATypeTag.SERIALIZED_DOUBLE_TYPE_TAG); + } + + resultStorage.reset(); + aInt32.setValue(intValue); + int32Ser.serialize(aInt32, out); + result.set(resultStorage); + } + + private int asInt(double d) throws HyracksDataException { + if (Double.isFinite(d)) { + long v = (long) d; + if (v == d && Integer.MIN_VALUE <= v && v <= Integer.MAX_VALUE) { + return (int) v; + } + } + throw new RuntimeDataException(ErrorCode.INTEGER_VALUE_EXPECTED, sourceLoc, d); + } + }; + } + }; + + } + + @Override + public FunctionIdentifier getIdentifier() { + return BuiltinFunctions.TREAT_AS_INTEGER; + } +} 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 25d90d3..04f4a1e 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 @@ -281,6 +281,7 @@ import org.apache.asterix.runtime.evaluators.functions.ToNumberDescriptor; import org.apache.asterix.runtime.evaluators.functions.ToObjectDescriptor; import org.apache.asterix.runtime.evaluators.functions.ToStringDescriptor; +import org.apache.asterix.runtime.evaluators.functions.TreatAsIntegerDescriptor; import org.apache.asterix.runtime.evaluators.functions.UUIDDescriptor; import org.apache.asterix.runtime.evaluators.functions.binary.BinaryConcatDescriptor; import org.apache.asterix.runtime.evaluators.functions.binary.BinaryLengthDescriptor; @@ -790,6 +791,8 @@ fc.addGenerated(ToObjectDescriptor.FACTORY); fc.addGenerated(ToStringDescriptor.FACTORY); + fc.addGenerated(TreatAsIntegerDescriptor.FACTORY); + // Cast function fc.addGenerated(CastTypeDescriptor.FACTORY); fc.addGenerated(CastTypeLaxDescriptor.FACTORY); -- To view, visit https://asterix-gerrit.ics.uci.edu/2788 To unsubscribe, visit https://asterix-gerrit.ics.uci.edu/settings Gerrit-MessageType: merged Gerrit-Change-Id: I986fab3e79b072aa2441af293f3e16c3f37bf508 Gerrit-PatchSet: 6 Gerrit-Project: asterixdb Gerrit-Branch: master Gerrit-Owner: Dmitry Lychagin <dmitry.lycha...@couchbase.com> Gerrit-Reviewer: Anon. E. Moose #1000171 Gerrit-Reviewer: Jenkins <jenk...@fulliautomatix.ics.uci.edu> Gerrit-Reviewer: Luo Chen <cl...@uci.edu> Gerrit-Reviewer: Taewoo Kim <wangs...@gmail.com> Gerrit-Reviewer: Till Westmann <ti...@apache.org> Gerrit-Reviewer: Xikui Wang <xkk...@gmail.com>