}
}
public static Split of( RexProgram program, RexBuilder rexBuilder )
{
final RexProgram program0 = program; // for debug
program = normalize( program, rexBuilder );
final List<Pair<Op, RexProgram>> list = new ArrayList<Pair<Op, RexProgram>>();
// Holds the previous link in the chain. The initial identity program is
// not used, but is a convenient place to hold the row type.
RexProgram previous = RexProgram.createIdentity( program.getInputRowType() );
for( int count = 0; program != null; count++ )
{
// We rely on unique field names everywhere. Otherwise all bets are off.
if( !unique( program.getInputRowType().getFieldNames() ) )
throw new AssertionError();
if( !unique( program.getOutputRowType().getFieldNames() ) )
throw new AssertionError();
if( program.equals( previous ) )
break;
// We should need no more than one call to each kind of operator (RENAME, RETAIN, etc.) so if
// we're not done now, we'll never be.
if( count > 10 )
throw new AssertionError( "program cannot be simplified after " + count + " iterations:" + program );
final Analyzed analyze = ProgramUtil.analyze( program );
if( analyze.isIdentity() )
break;
if( analyze.permutation != null && !analyze.permutation.isIdentity() )
{
if( analyze.hasConstants || analyze.hasFunctions )
throw new IllegalStateException( "permutation projection has constant and function transforms" );
final RexProgramBuilder builder = new RexProgramBuilder( previous.getOutputRowType(), rexBuilder );
for( int i = 0; i < analyze.permutation.getTargetCount(); i++ )
{
final int target = analyze.permutation.getTarget( i );
builder.addProject( target, null );
}
previous = builder.getProgram();
list.add( Pair.of( Op.RENAME, previous ) );
break;
}
if( analyze.isFilter() )
{
// Build a program that has a condition (a possibly complex expression)
// but projects all inputs.
final RexProgramBuilder builder = new RexProgramBuilder( previous.getOutputRowType(), rexBuilder );
builder.addIdentity();
builder.addCondition( program.gatherExpr( program.getCondition() ) );
previous = builder.getProgram();
list.add( Pair.of( Op.FILTER, previous ) );
// Remove condition from the remaining program.
final RexProgramBuilder builder2 = RexProgramBuilder.forProgram( program, rexBuilder, false );
builder2.clearCondition();
program = builder2.getProgram( true );
continue;
}
// TODO: remove "|| analyze.hasConstants" and generate a CONSTANTS slice
if( analyze.isComplex || analyze.hasFunctions || analyze.hasConstants )
{
previous = program;
list.add( Pair.of( Op.FUNCTION, previous ) );
break;
}
if( analyze.hasConstants )
{
final RexProgramBuilder builder = new RexProgramBuilder( previous.getOutputRowType(), rexBuilder );
if( true )
throw new AssertionError(); // TODO:
previous = builder.getProgram();
list.add( Pair.of( Op.CONSTANT, previous ) );
continue;
}
if( analyze.isOnlyRename )
{
// Create a program that projects all of its inputs, in order, but with different names.
final RexProgramBuilder builder = new RexProgramBuilder( previous.getOutputRowType(), rexBuilder );
final List<String> outputFieldNames = new ArrayList<String>( program.getInputRowType().getFieldNames() );
for( Ord<String> name : Ord.zip( program.getOutputRowType().getFieldNames() ) )
{
final int source = program.getSourceField( name.i );
if( source >= 0 )
outputFieldNames.set( source, name.e );
}
for( int i = 0; i < outputFieldNames.size(); i++ )
builder.addProject( i, outputFieldNames.get( i ) );
previous = builder.getProgram();
list.add( Pair.of( Op.RENAME, previous ) );
// We're done. Remaining program would be the identity.
break;
}
if( analyze.isRetainWithRename() )
{
final RexProgramBuilder builder = new RexProgramBuilder( previous.getOutputRowType(), rexBuilder );
builder.addIdentity();
builder.clearProjects();
for( RexLocalRef pair : program.getProjectList() )
{
final int index = pair.getIndex();
builder.addProject( index, program.getInputRowType().getFieldNames().get( index ) );
}
previous = builder.getProgram();
list.add( Pair.of( Op.RETAIN, previous ) );
// There may or may not be renames left.
program = RexProgram.createIdentity( previous.getOutputRowType(), program.getOutputRowType() );
continue;
}
throw new AssertionError( "program cannot be simplified: " + program );