/* * 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.impl.plan; import java.lang.StringBuilder; import java.util.ArrayList; import java.util.List; import org.apache.pig.impl.util.Pair; /** * A struct detailing how a projection is altered by an operator. */ public class RequiredFields { /** * Quick way for an operator to note that all columns from an input are required. */ private boolean mNeedAllFields = false; /** * Quick way for an operator to note that no columns from an input are required. */ private boolean mNeedNoFields = false; /** * List of fields required from the input. This includes fields that are * transformed, and thus are no longer the same fields. Using the example 'B * = foreach A generate $0, $2, $3, udf($1)' would produce the list (0, 0), * (0, 2), (0, 3), (0, 1). Note that the order is not guaranteed. */ private List<Pair<Integer, Integer>> mFields; /* * Required map keys information */ private List<MapKeysInfo> mMapKeysInfoList; /** * * @param needAllFields * to indicate if this required fields needs all the fields from * its input */ public RequiredFields(boolean needAllFields) { this(null, needAllFields, false); } /** * * @param needAllFields * to indicate if this required fields needs no fields from * its input */ public RequiredFields(boolean needAllFields, boolean needNoFields) { this(null, needAllFields, needNoFields); } /** * * @param fields * the list of input columns that are required */ public RequiredFields(List<Pair<Integer, Integer>> fields) { this(fields, false, false); } /** * * @param fields * the list of input columns that are required * @param needAllFields * to indicate if this required fields needs all the fields from * its input; cannot be true if needNoFields is true * @param needNoFields * to indicate if this required fields needs no fields from * its input; cannot be true if needAllFields is true */ private RequiredFields(List<Pair<Integer, Integer>> fields, boolean needAllFields, boolean needNoFields) { mFields = fields; if(needAllFields && needNoFields) { //both cannot be true //set both of them to false mNeedAllFields = false; mNeedNoFields = false; } else { mNeedAllFields = needAllFields; mNeedNoFields = needNoFields; } if (mFields!=null) { mMapKeysInfoList = new ArrayList<MapKeysInfo>(); for (int i=0;i<mFields.size();i++) mMapKeysInfoList.add(null); } } /** * * @return the list of input columns that are required */ public List<Pair<Integer, Integer>> getFields() { return mFields; } /** * @param i * the index of the required field * @return the ith required input column */ public Pair<Integer, Integer> getField(int i) { return mFields.get(i); } /** * * @return the size of required input columns */ public int size() { if (mFields==null) return 0; return mFields.size(); } /** * * @param fields * the list of input columns that are required */ public void setFields(List<Pair<Integer, Integer>> fields) { mFields = fields; if (mFields!=null) { mMapKeysInfoList = new ArrayList<MapKeysInfo>(); for (int i=0;i<mFields.size();i++) mMapKeysInfoList.add(null); } } /** * * @return if this required fields needs all the fields from its input(s) */ public boolean needAllFields() { return getNeedAllFields(); } /** * * @return if this required fields needs all the fields from its input(s) */ public boolean getNeedAllFields() { return mNeedAllFields; } /** * * @param needAllFields * to indicate if this required fields needs all the fields from * its input; cannot be true if needNoFields() is true */ public void setNeedAllFields(boolean needAllFields) { if(needAllFields && needNoFields()) return; mNeedAllFields = needAllFields; } /** * * @return if this required fields needs no fields from its input(s) */ public boolean needNoFields() { return getNeedNoFields(); } /** * * @return if this required fields needs no fields from its input(s) */ public boolean getNeedNoFields() { return mNeedNoFields; } /** * * @param needNoFields * to indicate if this required fields needs no fields from * its input; cannot be true if needAllFields() is true */ public void setNeedNoFields(boolean needNoFields) { if(needNoFields && needAllFields()) return; mNeedNoFields = needNoFields; } @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append("needAllFields: " + mNeedAllFields); sb.append(" needNoFields: " + mNeedNoFields); sb.append(" fields: " + mFields); return sb.toString(); } /** * Merge with RequiredFields r2. Merge both required fields and required map keys * @param r2 * Required fields to merge */ public void merge(RequiredFields r2) { if (r2 == null) return; if (getNeedAllFields()) return; if (r2.getNeedAllFields()) { mNeedAllFields = true; return; } if (getNeedNoFields() && !r2.getNeedNoFields()) { mNeedNoFields = false; } if (r2.getFields() == null) return; for (int i=0;i<r2.size();i++) { Pair<Integer, Integer> f = r2.getField(i); MapKeysInfo m = r2.getMapKeysInfo(i); if (mFields == null) { mFields = new ArrayList<Pair<Integer, Integer>>(); mMapKeysInfoList = new ArrayList<MapKeysInfo>(); } if (!mFields.contains(f)) { mFields.add(f); mMapKeysInfoList.add(m); mNeedNoFields = false; } else { if (m!=null) { int index = mFields.indexOf(new Pair<Integer, Integer>(f.first, f.second)); MapKeysInfo mapKeys = mMapKeysInfoList.get(index); if (mapKeys == null) mapKeys = new MapKeysInfo(); if (m.needAllKeys) { mapKeys.needAllKeys = true; mapKeys.keys = null; } else if (mapKeys.keys!=null) { if (m.keys!=null) mapKeys.keys.addAll(m.keys); } else { mapKeys.keys = m.keys; } mMapKeysInfoList.set(index, mapKeys); } } } return; } /** * Set the index of all fields to i * @param i * New index to set */ public void reIndex(int i) { if (mFields!=null) { for (Pair<Integer, Integer> p:mFields) { p.first = i; } } } /** * Merge another map key into existing required map keys list * @param input * The input of the field to merge * @param column * The column of the field to merge * @param key * The key to merge */ public void mergeMapKey(int input, int column, String key) { int index = mFields.indexOf(new Pair<Integer, Integer>(input, column)); if (index==-1) return; if (mMapKeysInfoList.get(index)==null) mMapKeysInfoList.set(index, new MapKeysInfo()); MapKeysInfo keysInfo = mMapKeysInfoList.get(index); if (keysInfo.needAllKeys) return; if (!keysInfo.keys.contains(key)) keysInfo.keys.add(key); } /** * Merge a MapKeysInfo structure to existing required map keys list * @param input * The input of the field to merge * @param column * The column of the field to merge * @param mapKeysInfo * The MapKeysInfo structure to merge */ public void mergeMapKeysInfo(int input, int column, MapKeysInfo mapKeysInfo) { if (mapKeysInfo == null) return; int index = mFields.indexOf(new Pair<Integer, Integer>(input, column)); if (index==-1) return; if (mMapKeysInfoList.get(index)==null) { mMapKeysInfoList.set(index, mapKeysInfo); return; } if (mapKeysInfo.needAllKeys) { mMapKeysInfoList.get(index).needAllKeys = true; mMapKeysInfoList.get(index).keys = null; } if (mapKeysInfo.keys!=null) { for (String key : mapKeysInfo.keys) mergeMapKey(input, column, key); } } /** * Set a MapKeysInfo structure to the required map keys list * @param input * The input of the field to set * @param column * The column of the field to set * @param mapKeysInfo * The MapKeysInfo structure to set */ public void setMapKeysInfo(int input, int column, MapKeysInfo mapKeysInfo) { int index = mFields.indexOf(new Pair<Integer, Integer>(input, column)); if (index==-1) return; mMapKeysInfoList.set(index, mapKeysInfo); } /** * Get the ith MapKeysInfo structure * @param i * The index of the MapKeysInfo, the index of MapKeysInfo is synchronized with mFields */ public MapKeysInfo getMapKeysInfo(int i) { return mMapKeysInfoList.get(i); } /** * Set the ith MapKeysInfo structure * @param i * The index of the MapKeysInfo, the index of MapKeysInfo is synchronized with mFields * @param mapKeysInfo * The MapKeysInfo to set */ public void setMapKeysInfo(int i, MapKeysInfo mapKeysInfo) { mMapKeysInfoList.set(i, mapKeysInfo); } }