blob: ef70fd1cd8a8d0eaa14861043e8ffcc93af6d074 [file] [log] [blame]
/*
* 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);
}
}