diff --git ql/src/java/org/apache/hadoop/hive/ql/optimizer/calcite/HiveCalciteUtil.java ql/src/java/org/apache/hadoop/hive/ql/optimizer/calcite/HiveCalciteUtil.java index 58a7cff..3c3d634 100644 --- ql/src/java/org/apache/hadoop/hive/ql/optimizer/calcite/HiveCalciteUtil.java +++ ql/src/java/org/apache/hadoop/hive/ql/optimizer/calcite/HiveCalciteUtil.java @@ -623,7 +623,7 @@ public static boolean isComparisonOp(RexCall call) { return call.getKind().belongsTo(SqlKind.COMPARISON); } - private static final Function REX_STR_FN = new Function() { + public static final Function REX_STR_FN = new Function() { public String apply(RexNode r) { return r.toString(); } diff --git ql/src/java/org/apache/hadoop/hive/ql/optimizer/calcite/HiveRexUtil.java ql/src/java/org/apache/hadoop/hive/ql/optimizer/calcite/HiveRexUtil.java index 3f6dd6a..27fc8e0 100644 --- ql/src/java/org/apache/hadoop/hive/ql/optimizer/calcite/HiveRexUtil.java +++ ql/src/java/org/apache/hadoop/hive/ql/optimizer/calcite/HiveRexUtil.java @@ -19,7 +19,9 @@ import java.util.ArrayList; import java.util.Collections; +import java.util.HashSet; import java.util.List; +import java.util.Set; import org.apache.calcite.linq4j.Ord; import org.apache.calcite.plan.RelOptUtil; @@ -35,6 +37,7 @@ import org.apache.calcite.util.Util; import com.google.common.collect.ImmutableList; +import com.google.common.collect.Lists; public class HiveRexUtil { @@ -145,11 +148,15 @@ private static RexNode simplifyCase(RexBuilder rexBuilder, RexCall call) { public static RexNode simplifyAnd(RexBuilder rexBuilder, RexCall e) { final List terms = RelOptUtil.conjunctions(e); final List notTerms = new ArrayList<>(); + final List negatedTerms = new ArrayList<>(); final List nullOperands = new ArrayList<>(); final List notNullOperands = new ArrayList<>(); - final List comparedOperands = new ArrayList<>(); + final Set comparedOperands = new HashSet<>(); for (int i = 0; i < terms.size(); i++) { final RexNode term = terms.get(i); + if (!HiveCalciteUtil.isDeterministic(term)) { + continue; + } switch (term.getKind()) { case NOT: notTerms.add( @@ -186,6 +193,14 @@ public static RexNode simplifyAnd(RexBuilder rexBuilder, RexCall e) { RexCall rightCast = (RexCall) right; comparedOperands.add(rightCast.getOperands().get(0)); } + RexCall negatedTerm = negate(rexBuilder, call); + if (negatedTerm != null) { + negatedTerms.add(negatedTerm); + RexCall invertNegatedTerm = invert(rexBuilder, negatedTerm); + if (invertNegatedTerm != null) { + negatedTerms.add(invertNegatedTerm); + } + } break; case IN: comparedOperands.add(((RexCall) term).operands.get(0)); @@ -230,9 +245,12 @@ public static RexNode simplifyAnd(RexBuilder rexBuilder, RexCall e) { // Example #1. x AND y AND z AND NOT (x AND y) - not satisfiable // Example #2. x AND y AND NOT (x AND y) - not satisfiable // Example #3. x AND y AND NOT (x AND y AND z) - may be satisfiable + final Set termsSet = new HashSet( + Lists.transform(terms, HiveCalciteUtil.REX_STR_FN)); for (RexNode notDisjunction : notTerms) { - final List terms2 = RelOptUtil.conjunctions(notDisjunction); - if (terms.containsAll(terms2)) { + final Set notSet = new HashSet( + Lists.transform(RelOptUtil.conjunctions(notDisjunction), HiveCalciteUtil.REX_STR_FN)); + if (termsSet.containsAll(notSet)) { return rexBuilder.makeLiteral(false); } } @@ -242,6 +260,14 @@ public static RexNode simplifyAnd(RexBuilder rexBuilder, RexCall e) { rexBuilder.makeCall( SqlStdOperatorTable.NOT, notDisjunction)); } + // The negated terms + for (RexNode notDisjunction : negatedTerms) { + final Set notSet = new HashSet( + Lists.transform(RelOptUtil.conjunctions(notDisjunction), HiveCalciteUtil.REX_STR_FN)); + if (termsSet.containsAll(notSet)) { + return rexBuilder.makeLiteral(false); + } + } return RexUtil.composeConjunction(rexBuilder, terms, false); } @@ -263,7 +289,40 @@ public static RexNode simplifyOr(RexBuilder rexBuilder, RexCall call) { } return RexUtil.composeDisjunction(rexBuilder, terms, false); } - - - + + private static RexCall negate(RexBuilder rexBuilder, RexCall call) { + switch (call.getKind()) { + case EQUALS: + return (RexCall) rexBuilder.makeCall(SqlStdOperatorTable.NOT_EQUALS, call.getOperands()); + case NOT_EQUALS: + return (RexCall) rexBuilder.makeCall(SqlStdOperatorTable.EQUALS, call.getOperands()); + case LESS_THAN: + return (RexCall) rexBuilder.makeCall(SqlStdOperatorTable.GREATER_THAN_OR_EQUAL, call.getOperands()); + case GREATER_THAN: + return (RexCall) rexBuilder.makeCall(SqlStdOperatorTable.LESS_THAN_OR_EQUAL, call.getOperands()); + case LESS_THAN_OR_EQUAL: + return (RexCall) rexBuilder.makeCall(SqlStdOperatorTable.GREATER_THAN, call.getOperands()); + case GREATER_THAN_OR_EQUAL: + return (RexCall) rexBuilder.makeCall(SqlStdOperatorTable.LESS_THAN, call.getOperands()); + } + return null; + } + + private static RexCall invert(RexBuilder rexBuilder, RexCall call) { + switch (call.getKind()) { + case LESS_THAN: + return (RexCall) rexBuilder.makeCall(SqlStdOperatorTable.GREATER_THAN, + Lists.reverse(call.getOperands())); + case GREATER_THAN: + return (RexCall) rexBuilder.makeCall(SqlStdOperatorTable.LESS_THAN, + Lists.reverse(call.getOperands())); + case LESS_THAN_OR_EQUAL: + return (RexCall) rexBuilder.makeCall(SqlStdOperatorTable.GREATER_THAN_OR_EQUAL, + Lists.reverse(call.getOperands())); + case GREATER_THAN_OR_EQUAL: + return (RexCall) rexBuilder.makeCall(SqlStdOperatorTable.LESS_THAN_OR_EQUAL, + Lists.reverse(call.getOperands())); + } + return null; + } } diff --git ql/src/java/org/apache/hadoop/hive/ql/optimizer/calcite/rules/HiveJoinPushTransitivePredicatesRule.java ql/src/java/org/apache/hadoop/hive/ql/optimizer/calcite/rules/HiveJoinPushTransitivePredicatesRule.java index 994af97..65a19e1 100644 --- ql/src/java/org/apache/hadoop/hive/ql/optimizer/calcite/rules/HiveJoinPushTransitivePredicatesRule.java +++ ql/src/java/org/apache/hadoop/hive/ql/optimizer/calcite/rules/HiveJoinPushTransitivePredicatesRule.java @@ -79,7 +79,7 @@ public HiveJoinPushTransitivePredicatesRule(Class clazz, @Override public void onMatch(RelOptRuleCall call) { Join join = call.rel(0); - + RelOptPredicateList preds = RelMetadataQuery.instance().getPulledUpPredicates(join); HiveRulesRegistry registry = call.getPlanner().getContext().unwrap(HiveRulesRegistry.class); diff --git ql/src/java/org/apache/hadoop/hive/ql/optimizer/calcite/rules/HiveReduceExpressionsRule.java ql/src/java/org/apache/hadoop/hive/ql/optimizer/calcite/rules/HiveReduceExpressionsRule.java index 8f15ec7..40c8191 100644 --- ql/src/java/org/apache/hadoop/hive/ql/optimizer/calcite/rules/HiveReduceExpressionsRule.java +++ ql/src/java/org/apache/hadoop/hive/ql/optimizer/calcite/rules/HiveReduceExpressionsRule.java @@ -142,17 +142,11 @@ public FilterReduceExpressionsRule(Class filterClass, // predicate to see if it was already a constant, // in which case we don't need any runtime decision // about filtering. + // TODO: support LogicalValues if (newConditionExp.isAlwaysTrue()) { call.transformTo( filter.getInput()); - } - // TODO: support LogicalValues - else if (newConditionExp instanceof RexLiteral - || RexUtil.isNullLiteral(newConditionExp, true)) { - // call.transformTo(call.builder().values(filter.getRowType()).build()); - return; - } - else if (reduced + } else if (reduced || !newConditionExp.toString().equals(filter.getCondition().toString())) { call.transformTo(call.builder(). push(filter.getInput()).filter(newConditionExp).build()); diff --git ql/src/java/org/apache/hadoop/hive/ql/optimizer/calcite/stats/HiveRelMdPredicates.java ql/src/java/org/apache/hadoop/hive/ql/optimizer/calcite/stats/HiveRelMdPredicates.java index 36d0b45..e810747 100644 --- ql/src/java/org/apache/hadoop/hive/ql/optimizer/calcite/stats/HiveRelMdPredicates.java +++ ql/src/java/org/apache/hadoop/hive/ql/optimizer/calcite/stats/HiveRelMdPredicates.java @@ -17,6 +17,15 @@ */ package org.apache.hadoop.hive.ql.optimizer.calcite.stats; +import java.util.ArrayList; +import java.util.BitSet; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.SortedMap; + import org.apache.calcite.linq4j.Linq4j; import org.apache.calcite.linq4j.Ord; import org.apache.calcite.linq4j.function.Predicate1; @@ -39,6 +48,7 @@ import org.apache.calcite.rex.RexInputRef; import org.apache.calcite.rex.RexLiteral; import org.apache.calcite.rex.RexNode; +import org.apache.calcite.rex.RexPermutationShuttle; import org.apache.calcite.rex.RexPermuteInputsShuttle; import org.apache.calcite.rex.RexShuttle; import org.apache.calcite.rex.RexUtil; @@ -61,18 +71,10 @@ import com.google.common.collect.Lists; import com.google.common.collect.Maps; -import java.util.ArrayList; -import java.util.BitSet; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.SortedMap; - //TODO: Move this to calcite public class HiveRelMdPredicates extends RelMdPredicates { + public static final RelMetadataProvider SOURCE = ReflectiveRelMetadataProvider.reflectiveSource( BuiltInMethod.PREDICATES.method, new HiveRelMdPredicates()); @@ -333,7 +335,14 @@ public RelOptPredicateList inferPredicates( for (RexNode iP : inferredPredicates) { ImmutableBitSet iPBitSet = RelOptUtil.InputFinder.bits(iP); - if (leftFieldsBitSet.contains(iPBitSet)) { + if (iPBitSet.isEmpty() && joinType == JoinRelType.INNER) { + leftInferredPredicates.add(iP); + rightInferredPredicates.add(iP); + } else if (iPBitSet.isEmpty() && joinType == JoinRelType.LEFT) { + rightInferredPredicates.add(iP); + } else if (iPBitSet.isEmpty() && joinType == JoinRelType.RIGHT) { + leftInferredPredicates.add(iP); + } else if (leftFieldsBitSet.contains(iPBitSet)) { leftInferredPredicates.add(iP.accept(leftPermute)); } else if (rightFieldsBitSet.contains(iPBitSet)) { rightInferredPredicates.add(iP.accept(rightPermute)); @@ -359,11 +368,11 @@ public RelOptPredicateList inferPredicates( case LEFT: return RelOptPredicateList.of( RelOptUtil.conjunctions(leftChildPredicates), - leftInferredPredicates, rightInferredPredicates); + EMPTY_LIST, rightInferredPredicates); case RIGHT: return RelOptPredicateList.of( RelOptUtil.conjunctions(rightChildPredicates), - inferredPredicates, EMPTY_LIST); + leftInferredPredicates, EMPTY_LIST); default: assert inferredPredicates.size() == 0; return RelOptPredicateList.EMPTY; @@ -382,6 +391,13 @@ private void infer(RexNode predicates, Set allExprsDigests, List inferedPredicates, boolean includeEqualityInference, ImmutableBitSet inferringFields) { for (RexNode r : RelOptUtil.conjunctions(predicates)) { + if (r.isAlwaysFalse()) { + RexLiteral falseVal = + joinRel.getCluster().getRexBuilder().makeLiteral(false); + inferedPredicates.add(falseVal); + allExprsDigests.add(falseVal.toString()); + continue; + } if (!includeEqualityInference && equalityPredicates.contains(r.toString())) { continue; diff --git ql/src/test/queries/clientpositive/constprog3.q ql/src/test/queries/clientpositive/constprog3.q new file mode 100644 index 0000000..2911fe2 --- /dev/null +++ ql/src/test/queries/clientpositive/constprog3.q @@ -0,0 +1,8 @@ +create temporary table table1(id int, val int, val1 int, dimid int); +create temporary table table3(id int, val int, val1 int); + +explain +select table1.id, table1.val, table1.val1 +from table1 inner join table3 +on table1.dimid = table3.id and table3.id = 1 where table1.dimid <> 1; + diff --git ql/src/test/queries/clientpositive/infer_join_preds.q ql/src/test/queries/clientpositive/infer_join_preds.q new file mode 100644 index 0000000..c2e0d09 --- /dev/null +++ ql/src/test/queries/clientpositive/infer_join_preds.q @@ -0,0 +1,61 @@ +-- SORT_QUERY_RESULTS + +explain +select * from src a join src1 b on a.key = b.key; + +select * from src a join src1 b on a.key = b.key; + +explain +select * from +(select * from src where 1 = 0)a +join +(select * from src1)b on a.key = b.key; + +select * from +(select * from src where 1 = 0)a +join +(select * from src1)b on a.key = b.key; + +explain +select * from +(select * from src where 1 = 0)a +left outer join +(select * from src1)b on a.key = b.key; + +select * from +(select * from src where 1 = 0)a +left outer join +(select * from src1)b on a.key = b.key; + +explain +select * from +(select * from src where 1 = 0)a +right outer join +(select * from src1)b on a.key = b.key; + +select * from +(select * from src where 1 = 0)a +right outer join +(select * from src1)b on a.key = b.key; + +explain +select * from +(select * from src where 1 = 0)a +full outer join +(select * from src1)b on a.key = b.key; + +select * from +(select * from src where 1 = 0)a +full outer join +(select * from src1)b on a.key = b.key; + +explain +select * from +(select * from src)a +right outer join +(select * from src1 where 1 = 0)b on a.key = b.key; + +select * from +(select * from src)a +right outer join +(select * from src1 where 1 = 0)b on a.key = b.key; diff --git ql/src/test/results/clientpositive/constprog3.q.out ql/src/test/results/clientpositive/constprog3.q.out new file mode 100644 index 0000000..e01a733 --- /dev/null +++ ql/src/test/results/clientpositive/constprog3.q.out @@ -0,0 +1,83 @@ +PREHOOK: query: create temporary table table1(id int, val int, val1 int, dimid int) +PREHOOK: type: CREATETABLE +PREHOOK: Output: database:default +PREHOOK: Output: default@table1 +POSTHOOK: query: create temporary table table1(id int, val int, val1 int, dimid int) +POSTHOOK: type: CREATETABLE +POSTHOOK: Output: database:default +POSTHOOK: Output: default@table1 +PREHOOK: query: create temporary table table3(id int, val int, val1 int) +PREHOOK: type: CREATETABLE +PREHOOK: Output: database:default +PREHOOK: Output: default@table3 +POSTHOOK: query: create temporary table table3(id int, val int, val1 int) +POSTHOOK: type: CREATETABLE +POSTHOOK: Output: database:default +POSTHOOK: Output: default@table3 +Warning: Shuffle Join JOIN[10][tables = [$hdt$_0, $hdt$_1]] in Stage 'Stage-1:MAPRED' is a cross product +PREHOOK: query: explain +select table1.id, table1.val, table1.val1 +from table1 inner join table3 +on table1.dimid = table3.id and table3.id = 1 where table1.dimid <> 1 +PREHOOK: type: QUERY +POSTHOOK: query: explain +select table1.id, table1.val, table1.val1 +from table1 inner join table3 +on table1.dimid = table3.id and table3.id = 1 where table1.dimid <> 1 +POSTHOOK: type: QUERY +STAGE DEPENDENCIES: + Stage-1 is a root stage + Stage-0 depends on stages: Stage-1 + +STAGE PLANS: + Stage: Stage-1 + Map Reduce + Map Operator Tree: + TableScan + alias: table1 + Statistics: Num rows: 1 Data size: 0 Basic stats: PARTIAL Column stats: NONE + Filter Operator + predicate: false (type: boolean) + Statistics: Num rows: 1 Data size: 0 Basic stats: PARTIAL Column stats: NONE + Select Operator + expressions: id (type: int), val (type: int), val1 (type: int) + outputColumnNames: _col0, _col1, _col2 + Statistics: Num rows: 1 Data size: 0 Basic stats: PARTIAL Column stats: NONE + Reduce Output Operator + sort order: + Statistics: Num rows: 1 Data size: 0 Basic stats: PARTIAL Column stats: NONE + value expressions: _col0 (type: int), _col1 (type: int), _col2 (type: int) + TableScan + alias: table3 + Statistics: Num rows: 1 Data size: 0 Basic stats: PARTIAL Column stats: COMPLETE + Select Operator + Statistics: Num rows: 1 Data size: 0 Basic stats: PARTIAL Column stats: COMPLETE + Filter Operator + predicate: false (type: boolean) + Statistics: Num rows: 1 Data size: 0 Basic stats: PARTIAL Column stats: COMPLETE + Reduce Output Operator + sort order: + Statistics: Num rows: 1 Data size: 0 Basic stats: PARTIAL Column stats: COMPLETE + Reduce Operator Tree: + Join Operator + condition map: + Inner Join 0 to 1 + keys: + 0 + 1 + outputColumnNames: _col0, _col1, _col2 + Statistics: Num rows: 1 Data size: 0 Basic stats: PARTIAL Column stats: NONE + File Output Operator + compressed: false + Statistics: Num rows: 1 Data size: 0 Basic stats: PARTIAL Column stats: NONE + table: + input format: org.apache.hadoop.mapred.SequenceFileInputFormat + output format: org.apache.hadoop.hive.ql.io.HiveSequenceFileOutputFormat + serde: org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe + + Stage: Stage-0 + Fetch Operator + limit: -1 + Processor Tree: + ListSink + diff --git ql/src/test/results/clientpositive/fold_case.q.out ql/src/test/results/clientpositive/fold_case.q.out index 90ea0af..d206682 100644 --- ql/src/test/results/clientpositive/fold_case.q.out +++ ql/src/test/results/clientpositive/fold_case.q.out @@ -117,18 +117,20 @@ STAGE PLANS: TableScan alias: src Statistics: Num rows: 500 Data size: 5312 Basic stats: COMPLETE Column stats: COMPLETE - Filter Operator - predicate: false (type: boolean) - Statistics: Num rows: 1 Data size: 0 Basic stats: PARTIAL Column stats: COMPLETE - Group By Operator - aggregations: count(1) - mode: hash - outputColumnNames: _col0 - Statistics: Num rows: 1 Data size: 8 Basic stats: COMPLETE Column stats: COMPLETE - Reduce Output Operator - sort order: + Select Operator + Statistics: Num rows: 500 Data size: 2000 Basic stats: COMPLETE Column stats: COMPLETE + Filter Operator + predicate: false (type: boolean) + Statistics: Num rows: 1 Data size: 4 Basic stats: COMPLETE Column stats: COMPLETE + Group By Operator + aggregations: count(1) + mode: hash + outputColumnNames: _col0 Statistics: Num rows: 1 Data size: 8 Basic stats: COMPLETE Column stats: COMPLETE - value expressions: _col0 (type: bigint) + Reduce Output Operator + sort order: + Statistics: Num rows: 1 Data size: 8 Basic stats: COMPLETE Column stats: COMPLETE + value expressions: _col0 (type: bigint) Reduce Operator Tree: Group By Operator aggregations: count(VALUE._col0) diff --git ql/src/test/results/clientpositive/infer_join_preds.q.out ql/src/test/results/clientpositive/infer_join_preds.q.out new file mode 100644 index 0000000..8afc905 --- /dev/null +++ ql/src/test/results/clientpositive/infer_join_preds.q.out @@ -0,0 +1,619 @@ +PREHOOK: query: -- SORT_QUERY_RESULTS + +explain +select * from src a join src1 b on a.key = b.key +PREHOOK: type: QUERY +POSTHOOK: query: -- SORT_QUERY_RESULTS + +explain +select * from src a join src1 b on a.key = b.key +POSTHOOK: type: QUERY +STAGE DEPENDENCIES: + Stage-1 is a root stage + Stage-0 depends on stages: Stage-1 + +STAGE PLANS: + Stage: Stage-1 + Map Reduce + Map Operator Tree: + TableScan + alias: a + Statistics: Num rows: 500 Data size: 5312 Basic stats: COMPLETE Column stats: NONE + Filter Operator + predicate: key is not null (type: boolean) + Statistics: Num rows: 500 Data size: 5312 Basic stats: COMPLETE Column stats: NONE + Select Operator + expressions: key (type: string), value (type: string) + outputColumnNames: _col0, _col1 + Statistics: Num rows: 500 Data size: 5312 Basic stats: COMPLETE Column stats: NONE + Reduce Output Operator + key expressions: _col0 (type: string) + sort order: + + Map-reduce partition columns: _col0 (type: string) + Statistics: Num rows: 500 Data size: 5312 Basic stats: COMPLETE Column stats: NONE + value expressions: _col1 (type: string) + TableScan + alias: b + Statistics: Num rows: 25 Data size: 191 Basic stats: COMPLETE Column stats: NONE + Filter Operator + predicate: key is not null (type: boolean) + Statistics: Num rows: 25 Data size: 191 Basic stats: COMPLETE Column stats: NONE + Select Operator + expressions: key (type: string), value (type: string) + outputColumnNames: _col0, _col1 + Statistics: Num rows: 25 Data size: 191 Basic stats: COMPLETE Column stats: NONE + Reduce Output Operator + key expressions: _col0 (type: string) + sort order: + + Map-reduce partition columns: _col0 (type: string) + Statistics: Num rows: 25 Data size: 191 Basic stats: COMPLETE Column stats: NONE + value expressions: _col1 (type: string) + Reduce Operator Tree: + Join Operator + condition map: + Inner Join 0 to 1 + keys: + 0 _col0 (type: string) + 1 _col0 (type: string) + outputColumnNames: _col0, _col1, _col2, _col3 + Statistics: Num rows: 550 Data size: 5843 Basic stats: COMPLETE Column stats: NONE + File Output Operator + compressed: false + Statistics: Num rows: 550 Data size: 5843 Basic stats: COMPLETE Column stats: NONE + table: + input format: org.apache.hadoop.mapred.SequenceFileInputFormat + output format: org.apache.hadoop.hive.ql.io.HiveSequenceFileOutputFormat + serde: org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe + + Stage: Stage-0 + Fetch Operator + limit: -1 + Processor Tree: + ListSink + +PREHOOK: query: select * from src a join src1 b on a.key = b.key +PREHOOK: type: QUERY +PREHOOK: Input: default@src +PREHOOK: Input: default@src1 +#### A masked pattern was here #### +POSTHOOK: query: select * from src a join src1 b on a.key = b.key +POSTHOOK: type: QUERY +POSTHOOK: Input: default@src +POSTHOOK: Input: default@src1 +#### A masked pattern was here #### +128 val_128 128 +128 val_128 128 +128 val_128 128 +146 val_146 146 val_146 +146 val_146 146 val_146 +150 val_150 150 val_150 +213 val_213 213 val_213 +213 val_213 213 val_213 +224 val_224 224 +224 val_224 224 +238 val_238 238 val_238 +238 val_238 238 val_238 +255 val_255 255 val_255 +255 val_255 255 val_255 +273 val_273 273 val_273 +273 val_273 273 val_273 +273 val_273 273 val_273 +278 val_278 278 val_278 +278 val_278 278 val_278 +311 val_311 311 val_311 +311 val_311 311 val_311 +311 val_311 311 val_311 +369 val_369 369 +369 val_369 369 +369 val_369 369 +401 val_401 401 val_401 +401 val_401 401 val_401 +401 val_401 401 val_401 +401 val_401 401 val_401 +401 val_401 401 val_401 +406 val_406 406 val_406 +406 val_406 406 val_406 +406 val_406 406 val_406 +406 val_406 406 val_406 +66 val_66 66 val_66 +98 val_98 98 val_98 +98 val_98 98 val_98 +PREHOOK: query: explain +select * from +(select * from src where 1 = 0)a +join +(select * from src1)b on a.key = b.key +PREHOOK: type: QUERY +POSTHOOK: query: explain +select * from +(select * from src where 1 = 0)a +join +(select * from src1)b on a.key = b.key +POSTHOOK: type: QUERY +STAGE DEPENDENCIES: + Stage-1 is a root stage + Stage-0 depends on stages: Stage-1 + +STAGE PLANS: + Stage: Stage-1 + Map Reduce + Map Operator Tree: + TableScan + alias: src + Statistics: Num rows: 500 Data size: 5312 Basic stats: COMPLETE Column stats: NONE + Filter Operator + predicate: false (type: boolean) + Statistics: Num rows: 1 Data size: 10 Basic stats: COMPLETE Column stats: NONE + Select Operator + expressions: key (type: string), value (type: string) + outputColumnNames: _col0, _col1 + Statistics: Num rows: 1 Data size: 10 Basic stats: COMPLETE Column stats: NONE + Reduce Output Operator + key expressions: _col0 (type: string) + sort order: + + Map-reduce partition columns: _col0 (type: string) + Statistics: Num rows: 1 Data size: 10 Basic stats: COMPLETE Column stats: NONE + value expressions: _col1 (type: string) + TableScan + alias: src1 + Statistics: Num rows: 25 Data size: 191 Basic stats: COMPLETE Column stats: NONE + Filter Operator + predicate: false (type: boolean) + Statistics: Num rows: 1 Data size: 7 Basic stats: COMPLETE Column stats: NONE + Select Operator + expressions: key (type: string), value (type: string) + outputColumnNames: _col0, _col1 + Statistics: Num rows: 1 Data size: 7 Basic stats: COMPLETE Column stats: NONE + Reduce Output Operator + key expressions: _col0 (type: string) + sort order: + + Map-reduce partition columns: _col0 (type: string) + Statistics: Num rows: 1 Data size: 7 Basic stats: COMPLETE Column stats: NONE + value expressions: _col1 (type: string) + Reduce Operator Tree: + Join Operator + condition map: + Inner Join 0 to 1 + keys: + 0 _col0 (type: string) + 1 _col0 (type: string) + outputColumnNames: _col0, _col1, _col2, _col3 + Statistics: Num rows: 1 Data size: 11 Basic stats: COMPLETE Column stats: NONE + File Output Operator + compressed: false + Statistics: Num rows: 1 Data size: 11 Basic stats: COMPLETE Column stats: NONE + table: + input format: org.apache.hadoop.mapred.SequenceFileInputFormat + output format: org.apache.hadoop.hive.ql.io.HiveSequenceFileOutputFormat + serde: org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe + + Stage: Stage-0 + Fetch Operator + limit: -1 + Processor Tree: + ListSink + +PREHOOK: query: select * from +(select * from src where 1 = 0)a +join +(select * from src1)b on a.key = b.key +PREHOOK: type: QUERY +PREHOOK: Input: default@src +PREHOOK: Input: default@src1 +#### A masked pattern was here #### +POSTHOOK: query: select * from +(select * from src where 1 = 0)a +join +(select * from src1)b on a.key = b.key +POSTHOOK: type: QUERY +POSTHOOK: Input: default@src +POSTHOOK: Input: default@src1 +#### A masked pattern was here #### +PREHOOK: query: explain +select * from +(select * from src where 1 = 0)a +left outer join +(select * from src1)b on a.key = b.key +PREHOOK: type: QUERY +POSTHOOK: query: explain +select * from +(select * from src where 1 = 0)a +left outer join +(select * from src1)b on a.key = b.key +POSTHOOK: type: QUERY +STAGE DEPENDENCIES: + Stage-1 is a root stage + Stage-0 depends on stages: Stage-1 + +STAGE PLANS: + Stage: Stage-1 + Map Reduce + Map Operator Tree: + TableScan + alias: src + Statistics: Num rows: 500 Data size: 5312 Basic stats: COMPLETE Column stats: NONE + Filter Operator + predicate: false (type: boolean) + Statistics: Num rows: 1 Data size: 10 Basic stats: COMPLETE Column stats: NONE + Select Operator + expressions: key (type: string), value (type: string) + outputColumnNames: _col0, _col1 + Statistics: Num rows: 1 Data size: 10 Basic stats: COMPLETE Column stats: NONE + Reduce Output Operator + key expressions: _col0 (type: string) + sort order: + + Map-reduce partition columns: _col0 (type: string) + Statistics: Num rows: 1 Data size: 10 Basic stats: COMPLETE Column stats: NONE + value expressions: _col1 (type: string) + TableScan + alias: src1 + Statistics: Num rows: 25 Data size: 191 Basic stats: COMPLETE Column stats: NONE + Filter Operator + predicate: false (type: boolean) + Statistics: Num rows: 1 Data size: 7 Basic stats: COMPLETE Column stats: NONE + Select Operator + expressions: key (type: string), value (type: string) + outputColumnNames: _col0, _col1 + Statistics: Num rows: 1 Data size: 7 Basic stats: COMPLETE Column stats: NONE + Reduce Output Operator + key expressions: _col0 (type: string) + sort order: + + Map-reduce partition columns: _col0 (type: string) + Statistics: Num rows: 1 Data size: 7 Basic stats: COMPLETE Column stats: NONE + value expressions: _col1 (type: string) + Reduce Operator Tree: + Join Operator + condition map: + Left Outer Join0 to 1 + keys: + 0 _col0 (type: string) + 1 _col0 (type: string) + outputColumnNames: _col0, _col1, _col2, _col3 + Statistics: Num rows: 1 Data size: 11 Basic stats: COMPLETE Column stats: NONE + File Output Operator + compressed: false + Statistics: Num rows: 1 Data size: 11 Basic stats: COMPLETE Column stats: NONE + table: + input format: org.apache.hadoop.mapred.SequenceFileInputFormat + output format: org.apache.hadoop.hive.ql.io.HiveSequenceFileOutputFormat + serde: org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe + + Stage: Stage-0 + Fetch Operator + limit: -1 + Processor Tree: + ListSink + +PREHOOK: query: select * from +(select * from src where 1 = 0)a +left outer join +(select * from src1)b on a.key = b.key +PREHOOK: type: QUERY +PREHOOK: Input: default@src +PREHOOK: Input: default@src1 +#### A masked pattern was here #### +POSTHOOK: query: select * from +(select * from src where 1 = 0)a +left outer join +(select * from src1)b on a.key = b.key +POSTHOOK: type: QUERY +POSTHOOK: Input: default@src +POSTHOOK: Input: default@src1 +#### A masked pattern was here #### +PREHOOK: query: explain +select * from +(select * from src where 1 = 0)a +right outer join +(select * from src1)b on a.key = b.key +PREHOOK: type: QUERY +POSTHOOK: query: explain +select * from +(select * from src where 1 = 0)a +right outer join +(select * from src1)b on a.key = b.key +POSTHOOK: type: QUERY +STAGE DEPENDENCIES: + Stage-1 is a root stage + Stage-0 depends on stages: Stage-1 + +STAGE PLANS: + Stage: Stage-1 + Map Reduce + Map Operator Tree: + TableScan + alias: src + Statistics: Num rows: 500 Data size: 5312 Basic stats: COMPLETE Column stats: NONE + Filter Operator + predicate: false (type: boolean) + Statistics: Num rows: 1 Data size: 10 Basic stats: COMPLETE Column stats: NONE + Select Operator + expressions: key (type: string), value (type: string) + outputColumnNames: _col0, _col1 + Statistics: Num rows: 1 Data size: 10 Basic stats: COMPLETE Column stats: NONE + Reduce Output Operator + key expressions: _col0 (type: string) + sort order: + + Map-reduce partition columns: _col0 (type: string) + Statistics: Num rows: 1 Data size: 10 Basic stats: COMPLETE Column stats: NONE + value expressions: _col1 (type: string) + TableScan + alias: src1 + Statistics: Num rows: 25 Data size: 191 Basic stats: COMPLETE Column stats: NONE + Select Operator + expressions: key (type: string), value (type: string) + outputColumnNames: _col0, _col1 + Statistics: Num rows: 25 Data size: 191 Basic stats: COMPLETE Column stats: NONE + Reduce Output Operator + key expressions: _col0 (type: string) + sort order: + + Map-reduce partition columns: _col0 (type: string) + Statistics: Num rows: 25 Data size: 191 Basic stats: COMPLETE Column stats: NONE + value expressions: _col1 (type: string) + Reduce Operator Tree: + Join Operator + condition map: + Right Outer Join0 to 1 + keys: + 0 _col0 (type: string) + 1 _col0 (type: string) + outputColumnNames: _col0, _col1, _col2, _col3 + Statistics: Num rows: 27 Data size: 210 Basic stats: COMPLETE Column stats: NONE + File Output Operator + compressed: false + Statistics: Num rows: 27 Data size: 210 Basic stats: COMPLETE Column stats: NONE + table: + input format: org.apache.hadoop.mapred.SequenceFileInputFormat + output format: org.apache.hadoop.hive.ql.io.HiveSequenceFileOutputFormat + serde: org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe + + Stage: Stage-0 + Fetch Operator + limit: -1 + Processor Tree: + ListSink + +PREHOOK: query: select * from +(select * from src where 1 = 0)a +right outer join +(select * from src1)b on a.key = b.key +PREHOOK: type: QUERY +PREHOOK: Input: default@src +PREHOOK: Input: default@src1 +#### A masked pattern was here #### +POSTHOOK: query: select * from +(select * from src where 1 = 0)a +right outer join +(select * from src1)b on a.key = b.key +POSTHOOK: type: QUERY +POSTHOOK: Input: default@src +POSTHOOK: Input: default@src1 +#### A masked pattern was here #### +NULL NULL +NULL NULL +NULL NULL +NULL NULL +NULL NULL val_165 +NULL NULL val_193 +NULL NULL val_265 +NULL NULL val_27 +NULL NULL val_409 +NULL NULL val_484 +NULL NULL 128 +NULL NULL 146 val_146 +NULL NULL 150 val_150 +NULL NULL 213 val_213 +NULL NULL 224 +NULL NULL 238 val_238 +NULL NULL 255 val_255 +NULL NULL 273 val_273 +NULL NULL 278 val_278 +NULL NULL 311 val_311 +NULL NULL 369 +NULL NULL 401 val_401 +NULL NULL 406 val_406 +NULL NULL 66 val_66 +NULL NULL 98 val_98 +PREHOOK: query: explain +select * from +(select * from src where 1 = 0)a +full outer join +(select * from src1)b on a.key = b.key +PREHOOK: type: QUERY +POSTHOOK: query: explain +select * from +(select * from src where 1 = 0)a +full outer join +(select * from src1)b on a.key = b.key +POSTHOOK: type: QUERY +STAGE DEPENDENCIES: + Stage-1 is a root stage + Stage-0 depends on stages: Stage-1 + +STAGE PLANS: + Stage: Stage-1 + Map Reduce + Map Operator Tree: + TableScan + alias: src + Statistics: Num rows: 500 Data size: 5312 Basic stats: COMPLETE Column stats: NONE + Filter Operator + predicate: false (type: boolean) + Statistics: Num rows: 1 Data size: 10 Basic stats: COMPLETE Column stats: NONE + Select Operator + expressions: key (type: string), value (type: string) + outputColumnNames: _col0, _col1 + Statistics: Num rows: 1 Data size: 10 Basic stats: COMPLETE Column stats: NONE + Reduce Output Operator + key expressions: _col0 (type: string) + sort order: + + Map-reduce partition columns: _col0 (type: string) + Statistics: Num rows: 1 Data size: 10 Basic stats: COMPLETE Column stats: NONE + value expressions: _col1 (type: string) + TableScan + alias: src1 + Statistics: Num rows: 25 Data size: 191 Basic stats: COMPLETE Column stats: NONE + Select Operator + expressions: key (type: string), value (type: string) + outputColumnNames: _col0, _col1 + Statistics: Num rows: 25 Data size: 191 Basic stats: COMPLETE Column stats: NONE + Reduce Output Operator + key expressions: _col0 (type: string) + sort order: + + Map-reduce partition columns: _col0 (type: string) + Statistics: Num rows: 25 Data size: 191 Basic stats: COMPLETE Column stats: NONE + value expressions: _col1 (type: string) + Reduce Operator Tree: + Join Operator + condition map: + Outer Join 0 to 1 + keys: + 0 _col0 (type: string) + 1 _col0 (type: string) + outputColumnNames: _col0, _col1, _col2, _col3 + Statistics: Num rows: 27 Data size: 210 Basic stats: COMPLETE Column stats: NONE + File Output Operator + compressed: false + Statistics: Num rows: 27 Data size: 210 Basic stats: COMPLETE Column stats: NONE + table: + input format: org.apache.hadoop.mapred.SequenceFileInputFormat + output format: org.apache.hadoop.hive.ql.io.HiveSequenceFileOutputFormat + serde: org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe + + Stage: Stage-0 + Fetch Operator + limit: -1 + Processor Tree: + ListSink + +PREHOOK: query: select * from +(select * from src where 1 = 0)a +full outer join +(select * from src1)b on a.key = b.key +PREHOOK: type: QUERY +PREHOOK: Input: default@src +PREHOOK: Input: default@src1 +#### A masked pattern was here #### +POSTHOOK: query: select * from +(select * from src where 1 = 0)a +full outer join +(select * from src1)b on a.key = b.key +POSTHOOK: type: QUERY +POSTHOOK: Input: default@src +POSTHOOK: Input: default@src1 +#### A masked pattern was here #### +NULL NULL +NULL NULL +NULL NULL +NULL NULL +NULL NULL val_165 +NULL NULL val_193 +NULL NULL val_265 +NULL NULL val_27 +NULL NULL val_409 +NULL NULL val_484 +NULL NULL 128 +NULL NULL 146 val_146 +NULL NULL 150 val_150 +NULL NULL 213 val_213 +NULL NULL 224 +NULL NULL 238 val_238 +NULL NULL 255 val_255 +NULL NULL 273 val_273 +NULL NULL 278 val_278 +NULL NULL 311 val_311 +NULL NULL 369 +NULL NULL 401 val_401 +NULL NULL 406 val_406 +NULL NULL 66 val_66 +NULL NULL 98 val_98 +PREHOOK: query: explain +select * from +(select * from src)a +right outer join +(select * from src1 where 1 = 0)b on a.key = b.key +PREHOOK: type: QUERY +POSTHOOK: query: explain +select * from +(select * from src)a +right outer join +(select * from src1 where 1 = 0)b on a.key = b.key +POSTHOOK: type: QUERY +STAGE DEPENDENCIES: + Stage-1 is a root stage + Stage-0 depends on stages: Stage-1 + +STAGE PLANS: + Stage: Stage-1 + Map Reduce + Map Operator Tree: + TableScan + alias: src + Statistics: Num rows: 500 Data size: 5312 Basic stats: COMPLETE Column stats: NONE + Filter Operator + predicate: false (type: boolean) + Statistics: Num rows: 1 Data size: 10 Basic stats: COMPLETE Column stats: NONE + Select Operator + expressions: key (type: string), value (type: string) + outputColumnNames: _col0, _col1 + Statistics: Num rows: 1 Data size: 10 Basic stats: COMPLETE Column stats: NONE + Reduce Output Operator + key expressions: _col0 (type: string) + sort order: + + Map-reduce partition columns: _col0 (type: string) + Statistics: Num rows: 1 Data size: 10 Basic stats: COMPLETE Column stats: NONE + value expressions: _col1 (type: string) + TableScan + alias: src1 + Statistics: Num rows: 25 Data size: 191 Basic stats: COMPLETE Column stats: NONE + Filter Operator + predicate: false (type: boolean) + Statistics: Num rows: 1 Data size: 7 Basic stats: COMPLETE Column stats: NONE + Select Operator + expressions: key (type: string), value (type: string) + outputColumnNames: _col0, _col1 + Statistics: Num rows: 1 Data size: 7 Basic stats: COMPLETE Column stats: NONE + Reduce Output Operator + key expressions: _col0 (type: string) + sort order: + + Map-reduce partition columns: _col0 (type: string) + Statistics: Num rows: 1 Data size: 7 Basic stats: COMPLETE Column stats: NONE + value expressions: _col1 (type: string) + Reduce Operator Tree: + Join Operator + condition map: + Right Outer Join0 to 1 + keys: + 0 _col0 (type: string) + 1 _col0 (type: string) + outputColumnNames: _col0, _col1, _col2, _col3 + Statistics: Num rows: 1 Data size: 11 Basic stats: COMPLETE Column stats: NONE + File Output Operator + compressed: false + Statistics: Num rows: 1 Data size: 11 Basic stats: COMPLETE Column stats: NONE + table: + input format: org.apache.hadoop.mapred.SequenceFileInputFormat + output format: org.apache.hadoop.hive.ql.io.HiveSequenceFileOutputFormat + serde: org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe + + Stage: Stage-0 + Fetch Operator + limit: -1 + Processor Tree: + ListSink + +PREHOOK: query: select * from +(select * from src)a +right outer join +(select * from src1 where 1 = 0)b on a.key = b.key +PREHOOK: type: QUERY +PREHOOK: Input: default@src +PREHOOK: Input: default@src1 +#### A masked pattern was here #### +POSTHOOK: query: select * from +(select * from src)a +right outer join +(select * from src1 where 1 = 0)b on a.key = b.key +POSTHOOK: type: QUERY +POSTHOOK: Input: default@src +POSTHOOK: Input: default@src1 +#### A masked pattern was here #### diff --git ql/src/test/results/clientpositive/mergejoin.q.out ql/src/test/results/clientpositive/mergejoin.q.out index f2c04e2..a85fd8b 100644 --- ql/src/test/results/clientpositive/mergejoin.q.out +++ ql/src/test/results/clientpositive/mergejoin.q.out @@ -2699,7 +2699,6 @@ full outer join PREHOOK: type: QUERY PREHOOK: Input: default@tab PREHOOK: Input: default@tab_part -PREHOOK: Input: default@tab_part@ds=2008-04-08 #### A masked pattern was here #### POSTHOOK: query: select * from (select * from tab where tab.key = 0)a @@ -2708,7 +2707,6 @@ full outer join POSTHOOK: type: QUERY POSTHOOK: Input: default@tab POSTHOOK: Input: default@tab_part -POSTHOOK: Input: default@tab_part@ds=2008-04-08 #### A masked pattern was here #### PREHOOK: query: select * from (select * from tab where tab.key = 0)a diff --git ql/src/test/results/clientpositive/partition_boolexpr.q.out ql/src/test/results/clientpositive/partition_boolexpr.q.out index 5272f33..fe33e18 100644 --- ql/src/test/results/clientpositive/partition_boolexpr.q.out +++ ql/src/test/results/clientpositive/partition_boolexpr.q.out @@ -274,19 +274,21 @@ STAGE PLANS: Map Operator Tree: TableScan alias: srcpart - Statistics: Num rows: 1 Data size: 0 Basic stats: PARTIAL Column stats: NONE - Filter Operator - predicate: false (type: boolean) - Statistics: Num rows: 1 Data size: 0 Basic stats: PARTIAL Column stats: NONE - Group By Operator - aggregations: count(1) - mode: hash - outputColumnNames: _col0 - Statistics: Num rows: 1 Data size: 8 Basic stats: COMPLETE Column stats: NONE - Reduce Output Operator - sort order: + Statistics: Num rows: 2000 Data size: 21248 Basic stats: COMPLETE Column stats: NONE + Select Operator + Statistics: Num rows: 2000 Data size: 21248 Basic stats: COMPLETE Column stats: NONE + Filter Operator + predicate: false (type: boolean) + Statistics: Num rows: 1 Data size: 10 Basic stats: COMPLETE Column stats: NONE + Group By Operator + aggregations: count(1) + mode: hash + outputColumnNames: _col0 Statistics: Num rows: 1 Data size: 8 Basic stats: COMPLETE Column stats: NONE - value expressions: _col0 (type: bigint) + Reduce Output Operator + sort order: + Statistics: Num rows: 1 Data size: 8 Basic stats: COMPLETE Column stats: NONE + value expressions: _col0 (type: bigint) Reduce Operator Tree: Group By Operator aggregations: count(VALUE._col0) diff --git ql/src/test/results/clientpositive/ppd_udf_col.q.out ql/src/test/results/clientpositive/ppd_udf_col.q.out index 2641f5c..a6310ed 100644 --- ql/src/test/results/clientpositive/ppd_udf_col.q.out +++ ql/src/test/results/clientpositive/ppd_udf_col.q.out @@ -109,17 +109,17 @@ STAGE PLANS: Map Operator Tree: TableScan alias: src - Statistics: Num rows: 500 Data size: 5312 Basic stats: COMPLETE Column stats: COMPLETE + Statistics: Num rows: 500 Data size: 5312 Basic stats: COMPLETE Column stats: NONE Filter Operator predicate: false (type: boolean) - Statistics: Num rows: 1 Data size: 0 Basic stats: PARTIAL Column stats: COMPLETE + Statistics: Num rows: 1 Data size: 10 Basic stats: COMPLETE Column stats: NONE Select Operator - expressions: '100' (type: string), rand() (type: double), '4' (type: string) + expressions: key (type: string), rand() (type: double), '4' (type: string) outputColumnNames: _col0, _col1, _col2 - Statistics: Num rows: 1 Data size: 0 Basic stats: PARTIAL Column stats: COMPLETE + Statistics: Num rows: 1 Data size: 10 Basic stats: COMPLETE Column stats: NONE File Output Operator compressed: false - Statistics: Num rows: 1 Data size: 0 Basic stats: PARTIAL Column stats: COMPLETE + Statistics: Num rows: 1 Data size: 10 Basic stats: COMPLETE Column stats: NONE table: input format: org.apache.hadoop.mapred.SequenceFileInputFormat output format: org.apache.hadoop.hive.ql.io.HiveSequenceFileOutputFormat @@ -284,17 +284,17 @@ STAGE PLANS: Map Operator Tree: TableScan alias: src - Statistics: Num rows: 500 Data size: 5312 Basic stats: COMPLETE Column stats: COMPLETE + Statistics: Num rows: 500 Data size: 5312 Basic stats: COMPLETE Column stats: NONE Filter Operator predicate: false (type: boolean) - Statistics: Num rows: 1 Data size: 0 Basic stats: PARTIAL Column stats: COMPLETE + Statistics: Num rows: 1 Data size: 10 Basic stats: COMPLETE Column stats: NONE Select Operator - expressions: '100' (type: string), rand() (type: double), '4' (type: string) + expressions: key (type: string), rand() (type: double), '4' (type: string) outputColumnNames: _col0, _col1, _col2 - Statistics: Num rows: 1 Data size: 0 Basic stats: PARTIAL Column stats: COMPLETE + Statistics: Num rows: 1 Data size: 10 Basic stats: COMPLETE Column stats: NONE File Output Operator compressed: false - Statistics: Num rows: 1 Data size: 0 Basic stats: PARTIAL Column stats: COMPLETE + Statistics: Num rows: 1 Data size: 10 Basic stats: COMPLETE Column stats: NONE table: input format: org.apache.hadoop.mapred.SequenceFileInputFormat output format: org.apache.hadoop.hive.ql.io.HiveSequenceFileOutputFormat diff --git ql/src/test/results/clientpositive/tez/mergejoin.q.out ql/src/test/results/clientpositive/tez/mergejoin.q.out index 14d0431..88a310f 100644 --- ql/src/test/results/clientpositive/tez/mergejoin.q.out +++ ql/src/test/results/clientpositive/tez/mergejoin.q.out @@ -2683,7 +2683,6 @@ full outer join PREHOOK: type: QUERY PREHOOK: Input: default@tab PREHOOK: Input: default@tab_part -PREHOOK: Input: default@tab_part@ds=2008-04-08 #### A masked pattern was here #### POSTHOOK: query: select * from (select * from tab where tab.key = 0)a @@ -2692,7 +2691,6 @@ full outer join POSTHOOK: type: QUERY POSTHOOK: Input: default@tab POSTHOOK: Input: default@tab_part -POSTHOOK: Input: default@tab_part@ds=2008-04-08 #### A masked pattern was here #### PREHOOK: query: select * from (select * from tab where tab.key = 0)a