/* * 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.pig.newplan.logical.expression; import java.util.List; import org.apache.pig.data.DataType; import org.apache.pig.impl.logicalLayer.FrontendException; import org.apache.pig.newplan.Operator; import org.apache.pig.newplan.OperatorPlan; import org.apache.pig.newplan.PlanVisitor; import org.apache.pig.newplan.logical.relational.LOForEach; import org.apache.pig.newplan.logical.relational.LOGenerate; import org.apache.pig.newplan.logical.relational.LOInnerLoad; import org.apache.pig.newplan.logical.relational.LogicalRelationalOperator; import org.apache.pig.newplan.logical.relational.LogicalSchema; import org.apache.pig.newplan.logical.relational.LogicalSchema.LogicalFieldSchema; /** * Projection of columns in an expression. * */ public class ProjectExpression extends ColumnExpression { private int input; // Which input of the relational operator this project // is projecting from. Count is zero based. So if this // project is in a filter the input number will always // be 0 (since filter has only one input). If it is // in a join, cross, cogroup, or union it could be // greater than 0. private int col; // The column in the input which the project references. // Count is zero based. private LogicalRelationalOperator attachedRelationalOp; /** * Adds projection to the plan. * @param plan LogicalExpressionPlan this projection will be a part of * @param inputNum Input number this project references. * @param colNum Column number this project references. */ public ProjectExpression(OperatorPlan plan, int inputNum, int colNum, LogicalRelationalOperator attachedRelationalOp) { super("Project", plan); input = inputNum; col = colNum; plan.add(this); this.attachedRelationalOp = attachedRelationalOp; } /** * @link org.apache.pig.newplan.Operator#accept(org.apache.pig.newplan.PlanVisitor) */ @Override public void accept(PlanVisitor v) throws FrontendException { if (!(v instanceof LogicalExpressionVisitor)) { throw new FrontendException("Expected LogicalExpressionVisitor", 2222); } ((LogicalExpressionVisitor)v).visit(this); } /** * Input number this project references. This is the input number for the * relational operator that contains this expression. The count is zero * based. * @return input number */ public int getInputNum() { return input; } public void setInputNum(int inputNum) { input = inputNum; } /** * Column number this project references. The column number is the column * in the relational operator that contains this expression. The count * is zero based. * @return column number */ public int getColNum() { return col; } /** * Set the column number for this project. This should only be called by * ProjectionPatcher. Stupid Java needs friends. * @param colNum new column number for projection */ public void setColNum(int colNum) { col = colNum; } public boolean isProjectStar() { return col<0; } @Override public LogicalSchema.LogicalFieldSchema getFieldSchema() throws FrontendException { if (fieldSchema!=null) return fieldSchema; LogicalRelationalOperator referent = findReferent(); LogicalSchema schema = referent.getSchema(); if (attachedRelationalOp instanceof LOGenerate && plan.getSuccessors(this)==null) { if (!(findReferent() instanceof LOInnerLoad)|| ((LOInnerLoad)findReferent()).sourceIsBag()) { String alias = findReferent().getAlias(); List<LOInnerLoad> innerLoads = LOForEach.findReacheableInnerLoadFromBoundaryProject(this); // pull tuple information from innerload if (innerLoads.get(0).getProjection().getFieldSchema().schema!=null && innerLoads.get(0).getProjection().getFieldSchema().schema.isTwoLevelAccessRequired()) { LogicalFieldSchema originalTupleFieldSchema = innerLoads.get(0).getProjection().getFieldSchema().schema.getField(0); LogicalFieldSchema newTupleFieldSchema = new LogicalFieldSchema(originalTupleFieldSchema.alias, schema, DataType.TUPLE); newTupleFieldSchema.uid = originalTupleFieldSchema.uid; LogicalSchema newTupleSchema = new LogicalSchema(); newTupleSchema.setTwoLevelAccessRequired(true); newTupleSchema.addField(newTupleFieldSchema); fieldSchema = new LogicalSchema.LogicalFieldSchema(alias, newTupleSchema, DataType.BAG); } else { fieldSchema = new LogicalSchema.LogicalFieldSchema(alias, schema, DataType.BAG); } fieldSchema.uid = innerLoads.get(0).getProjection().getFieldSchema().uid; } else { if (findReferent().getSchema()!=null) fieldSchema = findReferent().getSchema().getField(0); } if (fieldSchema!=null) uidOnlyFieldSchema = fieldSchema.mergeUid(uidOnlyFieldSchema); } else { if (schema == null) { fieldSchema = new LogicalSchema.LogicalFieldSchema(null, null, DataType.BYTEARRAY); uidOnlyFieldSchema = fieldSchema.mergeUid(uidOnlyFieldSchema); } else { int index = -1; if (!isProjectStar() && uidOnlyFieldSchema!=null) { long uid = uidOnlyFieldSchema.uid; for (int i=0;i<schema.size();i++) { LogicalFieldSchema fs = schema.getField(i); if (fs.uid==uid) { index = i; } } } if (index==-1) index = col; if (!isProjectStar()) { if (schema!=null && schema.size()>index) fieldSchema = schema.getField(index); else fieldSchema = new LogicalSchema.LogicalFieldSchema(null, null, DataType.BYTEARRAY); uidOnlyFieldSchema = fieldSchema.cloneUid(); } else { LogicalSchema newTupleSchema = null; if (schema!=null) newTupleSchema = schema.deepCopy(); fieldSchema = new LogicalSchema.LogicalFieldSchema(null, newTupleSchema, DataType.TUPLE); uidOnlyFieldSchema = fieldSchema.mergeUid(uidOnlyFieldSchema); } } } return fieldSchema; } /** * Find the LogicalRelationalOperator that this projection refers to. * @return LRO this projection refers to * @throws FrontendException */ public LogicalRelationalOperator findReferent() throws FrontendException { List<Operator> preds; preds = attachedRelationalOp.getPlan().getPredecessors(attachedRelationalOp); if (preds == null || input >= preds.size()) { throw new FrontendException("Projection with nothing to reference!", 2225); } LogicalRelationalOperator pred = (LogicalRelationalOperator)preds.get(input); if (pred == null) { throw new FrontendException("Cannot fine reference for " + this, 2226); } return pred; } @Override public boolean isEqual(Operator other) throws FrontendException { if (other != null && other instanceof ProjectExpression) { ProjectExpression po = (ProjectExpression)other; return po.input == input && po.col == col; } else { return false; } } public String toString() { StringBuilder msg = new StringBuilder(); if (fieldSchema!=null && fieldSchema.alias!=null) msg.append(fieldSchema.alias+":"); msg.append("(Name: " + name + " Type: "); if (fieldSchema!=null) msg.append(DataType.findTypeName(fieldSchema.type)); else msg.append("null"); msg.append(" Uid: "); if (fieldSchema!=null) msg.append(fieldSchema.uid); else msg.append("null"); msg.append(" Input: " + input + " Column: "); if (isProjectStar()) msg.append("(*)"); else msg.append(col); msg.append(")"); return msg.toString(); } public LogicalRelationalOperator getAttachedRelationalOp() { return attachedRelationalOp; } public void setAttachedRelationalOp(LogicalRelationalOperator attachedRelationalOp) { this.attachedRelationalOp = attachedRelationalOp; } @Override public byte getType() throws FrontendException { // for boundary project, if if (getFieldSchema()==null) { if (attachedRelationalOp instanceof LOGenerate && findReferent() instanceof LOInnerLoad) { if (((LOInnerLoad)findReferent()).getProjection().getColNum()==-1) return DataType.TUPLE; } return DataType.BYTEARRAY; } return super.getType(); } @Override public LogicalExpression deepCopy(LogicalExpressionPlan lgExpPlan) throws FrontendException { LogicalExpression copy = new ProjectExpression( lgExpPlan, this.getInputNum(), this.getColNum(), this.getAttachedRelationalOp()); return copy; } }