/* * 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.ArrayList; import java.util.List; import org.apache.pig.EvalFunc; import org.apache.pig.FuncSpec; import org.apache.pig.data.DataType; import org.apache.pig.impl.PigContext; import org.apache.pig.impl.logicalLayer.ExpressionOperator; import org.apache.pig.impl.logicalLayer.FrontendException; import org.apache.pig.impl.logicalLayer.LOConst; import org.apache.pig.impl.logicalLayer.LogicalOperator; import org.apache.pig.impl.logicalLayer.schema.Schema; import org.apache.pig.impl.logicalLayer.schema.Schema.FieldSchema; import org.apache.pig.newplan.Operator; import org.apache.pig.newplan.OperatorPlan; import org.apache.pig.newplan.PlanVisitor; import org.apache.pig.newplan.logical.Util; 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; public class UserFuncExpression extends LogicalExpression { private FuncSpec mFuncSpec; private Operator implicitReferencedOperator = null; private EvalFunc<?> ef = null; public UserFuncExpression(OperatorPlan plan, FuncSpec funcSpec) { super("UserFunc", plan); mFuncSpec = funcSpec; plan.add(this); } public FuncSpec getFuncSpec() { return mFuncSpec; } @Override public void accept(PlanVisitor v) throws FrontendException { if (!(v instanceof LogicalExpressionVisitor)) { throw new FrontendException("Expected LogicalExpressionVisitor", 2222); } ((LogicalExpressionVisitor)v).visit(this); } @Override public boolean isEqual(Operator other) throws FrontendException { if( other instanceof UserFuncExpression ) { UserFuncExpression exp = (UserFuncExpression)other; return mFuncSpec.equals(exp.mFuncSpec ); } else { return false; } } public List<LogicalExpression> getArguments() throws FrontendException { List<Operator> successors = null; List<LogicalExpression> args = new ArrayList<LogicalExpression>(); // try { successors = plan.getSuccessors(this); if(successors == null) return args; for(Operator lo : successors){ args.add((LogicalExpression)lo); } // } catch (FrontendException e) { // return args; // } return args; } /** * @param funcSpec the FuncSpec to set */ public void setFuncSpec(FuncSpec funcSpec) { mFuncSpec = funcSpec; } @Override public LogicalSchema.LogicalFieldSchema getFieldSchema() throws FrontendException { if (fieldSchema!=null) return fieldSchema; if(implicitReferencedOperator != null && mFuncSpec.getClassName().equals("org.apache.pig.impl.builtin.ReadScalars")){ // if this is a ReadScalars udf for scalar operation, use the // FieldSchema corresponding to this position in input List<Operator> args = plan.getSuccessors(this); if(args != null && args.size() > 0 ){ int pos = (Integer)((ConstantExpression)args.get(0)).getValue(); LogicalRelationalOperator inp = (LogicalRelationalOperator)implicitReferencedOperator; if( inp.getSchema() != null){ LogicalFieldSchema inpFs = inp.getSchema().getField(pos); fieldSchema = new LogicalFieldSchema(inpFs); // fieldSchema.alias = "ReadScalars_" + fieldSchema.alias; }else{ fieldSchema = new LogicalFieldSchema(null, null, DataType.BYTEARRAY); } return fieldSchema; }else{ //predecessors haven't been setup, return null return null; } } LogicalSchema inputSchema = new LogicalSchema(); List<Operator> succs = plan.getSuccessors(this); if (succs!=null) { for(Operator lo : succs){ if (((LogicalExpression)lo).getFieldSchema()==null) { inputSchema = null; break; } inputSchema.addField(((LogicalExpression)lo).getFieldSchema()); } } // Since ef only set one time, we never change its value, so we can optimize it by instantiate only once. // This significantly optimize the performance of frontend (PIG-1738) if (ef==null) ef = (EvalFunc<?>) PigContext.instantiateFuncFromSpec(mFuncSpec); Schema udfSchema = ef.outputSchema(Util.translateSchema(inputSchema)); if (udfSchema != null) { Schema.FieldSchema fs; if(udfSchema.size() == 0) { fs = new Schema.FieldSchema(null, null, DataType.findType(ef.getReturnType())); } else if(udfSchema.size() == 1) { fs = new Schema.FieldSchema(udfSchema.getField(0)); } else { fs = new Schema.FieldSchema(null, udfSchema, DataType.TUPLE); } fieldSchema = Util.translateFieldSchema(fs); } else { fieldSchema = new LogicalSchema.LogicalFieldSchema(null, null, DataType.findType(ef.getReturnType())); } uidOnlyFieldSchema = fieldSchema.mergeUid(uidOnlyFieldSchema); return fieldSchema; } public Operator getImplicitReferencedOperator() { return implicitReferencedOperator; } public void setImplicitReferencedOperator(Operator implicitReferencedOperator) { this.implicitReferencedOperator = implicitReferencedOperator; } @Override public LogicalExpression deepCopy(LogicalExpressionPlan lgExpPlan) throws FrontendException { UserFuncExpression copy = null; try { copy = new UserFuncExpression( lgExpPlan, this.getFuncSpec().clone() ); copy.setImplicitReferencedOperator(this.getImplicitReferencedOperator()); // Deep copy the input expressions. List<Operator> inputs = plan.getSuccessors( this ); if( inputs != null ) { for( Operator op : inputs ) { LogicalExpression input = (LogicalExpression)op; LogicalExpression inputCopy = input.deepCopy( lgExpPlan ); lgExpPlan.add( inputCopy ); lgExpPlan.connect( copy, inputCopy ); } } } catch(CloneNotSupportedException e) { e.printStackTrace(); } return copy; } public String toString() { StringBuilder msg = new StringBuilder(); msg.append("(Name: " + name + "(" + getFuncSpec() + ")" + " 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(")"); return msg.toString(); } }