Example #1
0
function JoinLHS($wpName, $jDesc)
{
    $rhsAttOrder = [];
    foreach ($jDesc->hash_RHS_attr as $attr) {
        $att = lookupAttribute($attr);
        $rhsAttOrder[$att->slot()] = $attr;
    }
    ksort($rhsAttOrder);
    $jDesc->hash_RHS_attr = $rhsAttOrder;
    ?>

//+{"kind":"WPF", "name":"LHS Lookup", "action":"start"}
extern "C"
int JoinLHSWorkFunc_<?php 
    echo $wpName;
    ?>
(WorkDescription &workDescription, ExecEngineData &result) {

    double start_time = global_clock.GetTime();
    PROFILING2_START;
    // this is the area where all of the intermediate, serialized records are stored
    SerializedSegmentArray serializedSegments [NUM_SEGS];

    // this is the area where all of the records are serialized to;
    // 10K bytes are initially used for this
    char *serializeHere = (char *) malloc (10000);

    // this is the output chunk
    Chunk output;

    // go to the work description and get the input chunk
    JoinLHSWorkDescription myWork;
    myWork.swap (workDescription);
    Chunk &input = myWork.get_chunkToProcess ();

    // get the waypoint ID from the chunk
    int wayPointID = myWork.get_wayPointID ();

    QueryIDSet queriesToRun = QueryExitsToQueries(myWork.get_whichQueryExits ());

<?php 
    cgAccessColumns($jDesc->attribute_queries_LHS, 'input', $wpName);
    ?>

    BStringIterator myInBStringIter;
    input.SwapBitmap (myInBStringIter);

    // start the iterators for the output columns for LHS; used only if stillShallow = 0
<?php 
    foreach ($jDesc->attribute_queries_LHS_copy as $att => $queries) {
        ?>
    <?php 
        echo attIteratorType($att);
        ?>
 <?php 
        echo $att;
        ?>
_Column_Out;
<?php 
    }
    /*foreach*/
    ?>

    // these manage the output columns that come from the RHS (now stored in the hash table)
<?php 
    cgConstructColumns(array_keys($jDesc->attribute_queries_RHS_copy));
    ?>

    // this is the ouput bitstring
    MMappedStorage myStore;
    Column bitmapOut (myStore);
    BStringIterator myOutBStringIter (bitmapOut, queriesToRun);

    // now we extract all of the hash table segments... after this, myEntries will hold them all
    HashTableView myView;
    myWork.get_centralHashTable ().EnterReader (myView);
    HashTableSegment myEntries[NUM_SEGS];
    myView.ExtractAllSegments (myEntries);

    // this tells us that we are "still shallow"---not making a deep copy of the LHS atts to the output
    int stillShallow = 1;

    // the bitstring that will be exracted from the hash table
    QueryIDSet *bitstringRHS = 0;

    QueryIDSet existsTarget(<?php 
    echo $jDesc->exists_target;
    ?>
, true);
    QueryIDSet notExistsTarget(<?php 
    echo $jDesc->not_exists_target;
    ?>
, true);

    // these are all of the attribute values that come from the hash table...
    // for each att we need a pointer as well as a dummy value that the pointer will be set to by default

<?php 
    foreach ($jDesc->attribute_queries_RHS as $att => $queries) {
        ?>
    QueryIDSet <?php 
        echo attQrys($att);
        ?>
_RHS(<?php 
        echo $queries;
        ?>
, true);
    <?php 
        echo attType($att);
        ?>
 <?php 
        echo $att;
        ?>
RHSShadow;
    <?php 
        echo attType($att);
        ?>
 *<?php 
        echo $att;
        ?>
RHS = NULL;
    <?php 
        echo attType($att);
        ?>
 <?php 
        echo $att;
        ?>
RHSobj;
<?php 
    }
    /*foreach*/
    ?>

    // now actually try to match up all of the tuples!
    int totalNum = 0;
    while (!myInBStringIter.AtEndOfColumn ()) { // TBD, probably this is not working TBD

        // counts how many matches for this query
        int numHits = 0;

        // extract values of attributes from streams
        // now go through the LHS input atts one at a time and extract if it is needed by an active query

        // see which queries match up
        QueryIDSet curBits = myInBStringIter.GetCurrent ();
        curBits.Intersect (queriesToRun);

        QueryIDSet exists; // keeps track of the queries for which a match is found
        QueryIDSet oldBitstringLHS; // last value of bistringLHS


        // if the input query is not empty
        if (!curBits.IsEmpty ()) {

            totalNum++;

            // compute the hash for LHS
            HT_INDEX_TYPE hashValue = HASH_INIT;
<?php 
    foreach ($jDesc->LHS_keys as $att) {
        ?>
            hashValue = CongruentHash(Hash(<?php 
        echo $att;
        ?>
_Column.GetCurrent()), hashValue);
<?php 
    }
    /*foreach*/
    ?>

            // figure out which of the hash buckets it goes into
            unsigned int index = WHICH_SEGMENT (hashValue);

            // now, go to that index and extract matching tuples!
            HT_INDEX_TYPE curSlot = WHICH_SLOT (hashValue);
            hashValue = curSlot;

            // this loops through all of the possible RHS hits
            while (1) {

                // this is the bitstring that will go in the output
                QueryIDSet bitstringLHS;

                // for safety (in case we look at a bitstring that spans multiple
                // entries that is not done being written by a concurrent writer)
                // empty out the inital bitstring
                ((QueryIDSet *) serializeHere)->Empty ();

                // give safe "shadow" values to all of the RHS attributes
<?php 
    foreach ($jDesc->hash_RHS_attr as $att) {
        ?>
                <?php 
        echo $att;
        ?>
RHS = &<?php 
        echo $att;
        ?>
RHSShadow;
<?php 
    }
    /*foreach*/
    ?>

                // here we go through and extract the atts one at a time from the hash
                // table.  Note that the atts must be extracted IN ORDER.  That is, the
                // bitstring is first, followed by the att mapped to the lowerest column
                // position, followed by the att mapped to the next lowest, and so on.

                // The Extract function pulls an attribute out of the hash table...
                int lenSoFar = 0, dummy, done;
                int lastLen = myEntries[index].Extract (serializeHere, curSlot, hashValue, wayPointID, BITMAP, dummy, done);

                // if we cannot find a bitstring, there was no tuple here, and we are done
                if (lastLen == 0) {
                    break;
                }

                // remember the bitstring
                bitstringRHS = (QueryIDSet *) serializeHere;
                lenSoFar += lastLen;

                // next look for other hashed attributes
<?php 
    foreach ($jDesc->hash_RHS_attr as $att) {
        ?>
                lastLen = myEntries[index].Extract (serializeHere + lenSoFar, curSlot, hashValue, wayPointID, <?php 
        echo attSlot($att);
        ?>
, dummy, done);

                // see if we got attribute
                if (lastLen > 0) {
                    Deserialize(serializeHere + lenSoFar, <?php 
        echo $att;
        ?>
RHSobj);
                    //<?php 
        echo attOptimizedDeserialize($att, $att . "RHSobj", "serializeHere", "lenSoFar");
        ?>
;
                    <?php 
        echo $att;
        ?>
RHS = &<?php 
        echo $att;
        ?>
RHSobj;
                    lenSoFar += lastLen;
                } else {
                    FATALIF(<?php 
        echo attQrys($att);
        ?>
_RHS.Overlaps(*bitstringRHS),
                        "Did not find attribute <?php 
        echo $att;
        ?>
 in active RHS tuple");
                }
<?php 
    }
    /*foreach*/
    ?>

                // see if we have any query matches
                bitstringRHS->Intersect (curBits);
                QueryIDSet qBits;
                //printf("TPLLLLL: cust_acctbal = %f    orders_custkey = %d   cust_custkey = %d\n", *customer_c_acctbalRHS, orders_o_custkey_Column.GetCurrent(), *customer_c_custkeyRHS);

<?php 
    foreach ($jDesc->queries_attribute_comparison as $qClass) {
        ?>
                // See if any query in query class is eligible for this comparision
                qBits = QueryIDSet(<?php 
        echo $qClass->qClass;
        ?>
, true);
                qBits.Intersect(*bitstringRHS);
                if (
                    !qBits.IsEmpty () &&

    <?php 
        foreach ($qClass->att_pairs as $pair) {
            ?>
                     *<?php 
            echo $pair->rhs;
            ?>
RHS == <?php 
            echo $pair->lhs;
            ?>
_Column.GetCurrent() &&
    <?php 
        }
        /*foreach pair*/
        ?>
                     1 )
                {
                    bitstringLHS.Union (qBits);
                }
<?php 
    }
    /*foreach query class*/
    ?>

                // if any of them hit...
                if (!bitstringLHS.IsEmpty ()) {

                    exists.Union(bitstringLHS);

                    numHits++;

                    // see if we need to move from shallow to deep
                    if (numHits == 2 && stillShallow) {

<?php 
    foreach ($jDesc->attribute_queries_LHS_copy as $att => $qrys) {
        ?>
                        <?php 
        echo attData($att);
        ?>
_Out.CreateDeepCopy (<?php 
        echo attData($att);
        ?>
);
                        <?php 
        echo attData($att);
        ?>
_Out.Insert (<?php 
        echo attData($att);
        ?>
.GetCurrent());
                        <?php 
        echo attData($att);
        ?>
_Out.Advance();

<?php 
    }
    /*foreach*/
    ?>
                        stillShallow = 0;
                    }

                    // now, add all of the outputs over... first deal with the LHS input atts
                    // that get copied into output atts
                    if (!stillShallow) {
<?php 
    foreach ($jDesc->attribute_queries_LHS_copy as $att => $qrys) {
        ?>
                        <?php 
        echo attData($att);
        ?>
_Out.Insert (<?php 
        echo attData($att);
        ?>
.GetCurrent());
                        <?php 
        echo attData($att);
        ?>
_Out.Advance();

<?php 
    }
    /*foreach*/
    ?>
                    }

                    // now, deal with the output atts that come from the hash table
<?php 
    foreach ($jDesc->attribute_queries_RHS_copy as $att => $qrys) {
        ?>
                    <?php 
        echo attData($att);
        ?>
_Out.Insert (*<?php 
        echo $att;
        ?>
RHS);
                    <?php 
        echo attData($att);
        ?>
_Out.Advance();
<?php 
    }
    /*foreach*/
    ?>


                    // finally, set the bitmap. We are one element behind
                    if (!oldBitstringLHS.IsEmpty()){
                         myOutBStringIter.Insert (oldBitstringLHS);
                                 myOutBStringIter.Advance ();
                    }
                    oldBitstringLHS=bitstringLHS;
                }  // empty bistring
            }
        }

    // compute the true exist queries
    QueryIDSet tmp = existsTarget;
    tmp.Intersect(exists);
    tmp.Intersect(curBits); // not needed but I'm paranoid

    // compute the true not exits queries
    QueryIDSet tmp2 = curBits;
    tmp2.Intersect(notExistsTarget);
    tmp2.Difference(exists);

    // now put everything in bitstringLHS
    oldBitstringLHS.Union(tmp);
    oldBitstringLHS.Union(tmp2);

    if (!oldBitstringLHS.IsEmpty()){
             myOutBStringIter.Insert (oldBitstringLHS);
                 myOutBStringIter.Advance ();
        }


        // at this point, we are done trying to join this tuple... any join results have been
        // written to the output columns.  Note that we don't have to advance in the output data
        // columns; if we are shallow, we don't touch the output columns.  If we are not shallow,
        // if there were no results, we have nothing to write.  HOWEVER, if we are shallow and
        // we did not get a match, we need to add an empty btstring
        if (stillShallow && numHits == 0) {
<?php 
    foreach ($jDesc->attribute_queries_RHS_copy as $att => $qrys) {
        ?>
            <?php 
        echo attType($att);
        ?>
 tmp_<?php 
        echo attData($att);
        ?>
;
            <?php 
        echo attData($att);
        ?>
_Out.Insert (tmp_<?php 
        echo attData($att);
        ?>
);
            <?php 
        echo attData($att);
        ?>
_Out.Advance();
<?php 
    }
    /*foreach*/
    ?>

        if (oldBitstringLHS.IsEmpty()){ // no not exist and no join match
           myOutBStringIter.Insert (oldBitstringLHS);
               myOutBStringIter.Advance ();
        }
        }

        // lastly, we need to advance in the INPUT tuples
<?php 
    foreach ($jDesc->attribute_queries_LHS as $att => $qrys) {
        ?>
        <?php 
        echo attData($att);
        ?>
.Advance();
<?php 
    }
    /*foreach*/
    ?>

        // advance the input bitstring
        myInBStringIter.Advance ();
    }

    // DONE!  So construct the output tuple

    // if we are still shallow, put the original data into the output
    if (stillShallow) {
<?php 
    foreach ($jDesc->attribute_queries_LHS_copy as $att => $qrys) {
        ?>
        Column col_<?php 
        echo $att;
        ?>
;
        <?php 
        echo attData($att);
        ?>
.Done(col_<?php 
        echo $att;
        ?>
);
        output.SwapColumn (col_<?php 
        echo $att;
        ?>
, <?php 
        echo attSlot($att);
        ?>
);
<?php 
    }
    /*foreach*/
    ?>
    } else {
<?php 
    foreach ($jDesc->attribute_queries_LHS_copy as $att => $qrys) {
        ?>
        Column col_<?php 
        echo $att;
        ?>
;
        <?php 
        echo attData($att);
        ?>
_Out.Done(col_<?php 
        echo $att;
        ?>
);
        output.SwapColumn (col_<?php 
        echo $att;
        ?>
, <?php 
        echo attSlot($att);
        ?>
);
<?php 
    }
    /*foreach*/
    ?>
    }

    {
<?php 
    foreach ($jDesc->attribute_queries_RHS_copy as $att => $qrys) {
        ?>
        Column col_<?php 
        echo $att;
        ?>
;
        <?php 
        echo attData($att);
        ?>
_Out.Done(col_<?php 
        echo $att;
        ?>
);
        output.SwapColumn (col_<?php 
        echo $att;
        ?>
, <?php 
        echo attSlot($att);
        ?>
);
<?php 
    }
    /*foreach*/
    ?>
    }

    // put in the output bitmap
    myOutBStringIter.Done ();
    output.SwapBitmap (myOutBStringIter);

    // and give back the result
    ChunkContainer tempResult (output);
    tempResult.swap (result);

    PROFILING2_END;

    PROFILING(start_time, "<?php 
    echo $wpName;
    ?>
", "LHS_lookup", "%d", totalNum);
    PROFILING(0.0, "HashTable", "fillrate", "%2.4f", HashTableSegment::globalFillRate*100.0);

    // Finish performance counters
    // Use the Set functionality in case we add additional counters later.
    PCounterList counterList;
    PCounter totalCnt("tpi lhs", totalNum, "<?php 
    echo $wpName;
    ?>
");
    counterList.Append(totalCnt);

    PROFILING2_SET(counterList, "<?php 
    echo $wpName;
    ?>
");

    int64_t hFillRate = int64_t(HashTableSegment::globalFillRate * 1000);
    PROFILING2_INSTANT("hfr", hFillRate, "global");

    free (serializeHere);
    return 1;
}
//+{"kind":"WPF", "name":"LHS Lookup", "action":"end"}

<?php 
}
Example #2
0
function GLAGenerate_Finalize($wpName, $queries, $attMap)
{
    ?>
#ifndef PER_QUERY_PROFILE
#define PER_QUERY_PROFILE
#endif

//+{"kind":"WPF", "name":"Finalize (Chunk)", "action":"start"}
extern "C"
int GLAFinalizeWorkFunc_<?php 
    echo $wpName;
    ?>
(WorkDescription &workDescription, ExecEngineData &result) {
    GLAFinalizeWD myWork;
    myWork.swap (workDescription);
    QueryExit whichOne = myWork.get_whichQueryExit();
    GLAState& glaState = myWork.get_glaState();
<?php 
    cgDeclareQueryIDs($queries);
    ?>

    // Set up the output chunk
    Chunk output;

    QueryIDSet queriesToRun = whichOne.query;
<?php 
    // Extract the state for the query
    foreach ($queries as $query => $info) {
        $gla = $info['gla'];
        ?>
    // Do query <?php 
        echo queryName($query);
        ?>
:
    <?php 
        echo $gla;
        ?>
 * state_<?php 
        echo queryName($query);
        ?>
 = NULL;
    if( whichOne.query == <?php 
        echo queryName($query);
        ?>
 ) {
        // Look for the state of query <?php 
        echo queryName($query);
        ?>
.
        GLAPtr state;
        state.swap(glaState);
        FATALIF( state.get_glaType() != <?php 
        echo $gla->cHash();
        ?>
,
            "Got GLA of unexpected type");
        state_<?php 
        echo queryName($query);
        ?>
 = (<?php 
        echo $gla;
        ?>
 *) state.get_glaPtr();
    }
<?php 
    }
    // foreach query
    ?>

    // Start columns for all possible outputs.
<?php 
    foreach ($queries as $query => $info) {
        $output = $info['output'];
        cgConstructColumns($output);
    }
    // foreach query
    ?>

    // This is the output bitstring
    MMappedStorage myStore;
    Column bitmapOut( myStore );
    BStringIterator myOutBStringIter( bitmapOut, queriesToRun );

    PROFILING2_START;
    int64_t numTuples = 0;

#ifdef PER_QUERY_PROFILE
<?php 
    foreach ($queries as $query => $info) {
        ?>
    int64_t numTuples_<?php 
        echo queryName($query);
        ?>
 = 0;
<?php 
    }
    // foreach query
    ?>
#endif // PER_QUERY_PROFILE

    // Extract results
<?php 
    foreach ($queries as $query => $info) {
        $gla = $info['gla'];
        $output = $info['output'];
        // If this is true, we return the GLA as a const state.
        // Otherwise, we pack the results into a chunk.
        $retState = $info['retState'];
        $stateName = 'state_' . queryName($query);
        ?>
    if( whichOne.query == <?php 
        echo queryName($query);
        ?>
 ) {
<?php 
        if ($retState) {
            ?>
        FATAL( "Called normal finalize for query that was supposed to be returned as a const state" );
<?php 
        } else {
            $resType = $gla->result_type();
            $resType = get_first_value($resType, ['fragment', 'multi', 'single', 'state']);
            if ($resType == 'single') {
                ?>
        <?php 
                echo $stateName;
                ?>
->GetResult(<?php 
                echo implode(', ', $output);
                ?>
);
        numTuples++;
#ifdef PER_QUERY_PROFILE
        numTuples_<?php 
                echo queryName($query);
                ?>
++;
#endif // PER_QUERY_PROFILE
        myOutBStringIter.Insert(<?php 
                echo queryName($query);
                ?>
);
        myOutBStringIter.Advance();
<?php 
                cgInsertAttributesList($output, '_Column_Out', 2);
            } elseif ($resType == 'multi') {
                ?>
        <?php 
                echo $stateName;
                ?>
->Finalize();
        while( <?php 
                echo $stateName;
                ?>
->GetNextResult(<?php 
                echo implode(', ', $output);
                ?>
) ) {
            numTuples++;
#ifdef PER_QUERY_PROFILE
            numTuples_<?php 
                echo queryName($query);
                ?>
++;
#endif // PER_QUERY_PROFILE
            myOutBStringIter.Insert(<?php 
                echo queryName($query);
                ?>
);
            myOutBStringIter.Advance();
<?php 
                cgInsertAttributesList($output, '_Column_Out', 3);
                ?>
        }
<?php 
            } elseif ($resType == 'fragment') {
                ?>
        int fragment = myWork.get_fragmentNo();
        <?php 
                echo $gla;
                ?>
_Iterator * iterator = <?php 
                echo $stateName;
                ?>
->Finalize(fragment);
        while( <?php 
                echo $stateName;
                ?>
->GetNextResult(iterator, <?php 
                echo implode(', ', $output);
                ?>
) ) {
            numTuples++;
#ifdef PER_QUERY_PROFILE
            numTuples_<?php 
                echo queryName($query);
                ?>
++;
#endif // PER_QUERY_PROFILE
            myOutBStringIter.Insert(<?php 
                echo queryName($query);
                ?>
);
            myOutBStringIter.Advance();
<?php 
                cgInsertAttributesList($output, '_Column_Out', 3);
                ?>
        }
        delete iterator;
<?php 
            } elseif ($resType == 'state') {
                reset($output);
                $att = current($output);
                // Output attribute
                if ($gla->finalize_as_state()) {
                    ?>
        <?php 
                    echo $stateName;
                    ?>
->FinalizeState();
<?php 
                }
                // if GLA finalized as state
                ?>
        <?php 
                echo $att;
                ?>
 = <?php 
                echo $att->type();
                ?>
( <?php 
                echo $stateName;
                ?>
 );
        numTuples++;
#ifdef PER_QUERY_PROFILE
        numTuples_<?php 
                echo queryName($query);
                ?>
++;
#endif // PER_QUERY_PROFILE
        myOutBStringIter.Insert(<?php 
                echo queryName($query);
                ?>
);
        myOutBStringIter.Advance();
<?php 
                cgInsertAttributesList($output, '_Column_Out', 2);
            } else {
                grokit_error('GLA ' . $gla . ' has no known result type: [' . implode(',', $resType) . ']');
            }
            // switch GLA result type
        }
        // else GLA produces into a chunk
        ?>
        myOutBStringIter.Done();
        output.SwapBitmap(myOutBStringIter);

        // Write columns
<?php 
        foreach ($output as $att) {
            ?>
        Column col_<?php 
            echo $att;
            ?>
;
        <?php 
            echo $att;
            ?>
_Column_Out.Done(col_<?php 
            echo $att;
            ?>
);
        output.SwapColumn( col_<?php 
            echo $att;
            ?>
, <?php 
            echo $att->slot();
            ?>
 );
<?php 
        }
        // foreach output attribute
        ?>
    }
<?php 
    }
    // foreach query
    ?>

    PROFILING2_END;

    PCounterList counterList;
    PCounter totalCnt("tpo", numTuples, "<?php 
    echo $wpName;
    ?>
");
    counterList.Append(totalCnt);

#ifdef PER_QUERY_PROFILE
<?php 
    foreach ($queries as $query => $info) {
        ?>
    {
        PCounter qCount("tpo <?php 
        echo queryName($query);
        ?>
", numTuples_<?php 
        echo queryName($query);
        ?>
, "<?php 
        echo $wpName;
        ?>
");
        counterList.Append(qCount);
    }
<?php 
    }
    // foreach query
    ?>
#endif // PER_QUERY_PROFILE

    PROFILING2_SET(counterList, "<?php 
    echo $wpName;
    ?>
");

    ChunkContainer tempResult(output);
    tempResult.swap(result);
    return WP_FINALIZE;
}
//+{"kind":"WPF", "name":"Finalize (Chunk)", "action":"end"}
<?php 
}
Example #3
0
function GTGenerate_ProcessChunk($wpName, $queries, $attMap)
{
    $allPassthrough = [];
    $allSynth = [];
    foreach ($queries as $query => $info) {
        $pass = $info['pass'];
        foreach ($pass as $attr) {
            if (!in_array($attr, $allPassthrough)) {
                $allPassthrough[] = $attr;
            }
        }
        $output = $info['output'];
        foreach ($output as $attr) {
            if (!in_array($attr, $allSynth)) {
                $allSynth[] = $attr;
            }
        }
    }
    $gtVars = [];
    ?>
//+{"kind":"WPF", "name":"Process Chunk", "action":"start"}
extern "C"
int GTProcessChunkWorkFunc_<?php 
    echo $wpName;
    ?>
(WorkDescription & workDescription, ExecEngineData & result) {
    GTProcessChunkWD myWork;
    myWork.swap(workDescription);

    Chunk & input = myWork.get_chunkToProcess();

    QueryToGLAStateMap & gtStates = myWork.get_gtStates();
    QueryToGLAStateMap & constStates = myWork.get_constStates();

    QueryIDSet queriesToRun = QueryExitsToQueries( myWork.get_whichQueryExits() );
    FATALIF(queriesToRun.IsEmpty(), "Attempted to process chunk with no queries to run.");

<?php 
    cgDeclareQueryIDs($queries);
    ?>

    QueryIDSet queriesAvailable;
<?php 
    foreach ($queries as $query => $info) {
        ?>
    queriesAvailable.Union(<?php 
        echo queryName($query);
        ?>
);
<?php 
    }
    // for each query
    ?>

    QueryIDSet queriesCovered = queriesToRun;
    queriesCovered.Intersect(queriesAvailable);

    FATALIF( queriesCovered.IsEmpty(), "Queries being run do not overlap queries known by this waypoint" );

    PROFILING2_START;

    // Set up the output chunk
    Chunk output;

    // Defining the GT states needed.
    // For each one we will look for an existing state, if we find none, we
    // create a new state from scratch.

<?php 
    foreach ($queries as $query => $info) {
        $gt = $info['gt'];
        $gtVar = 'state_' . queryName($query);
        $gtVars[$query] = $gtVar;
        $cstArgs = [];
        if ($gt->configurable()) {
            echo '    // JSON Configuration for query ' . queryName($query) . PHP_EOL;
            $carg = $info['cargs'];
            $carg->init();
            $cstArgs[] = $carg->name();
            echo PHP_EOL;
        }
        if ($gt->has_state()) {
            $cstArgs[] = '*constState';
        }
        if (\count($cstArgs) > 0) {
            $cstStr = '(' . implode(', ', $cstArgs) . ')';
        } else {
            $cstStr = '';
        }
        ?>
    <?php 
        echo $gt;
        ?>
 * <?php 
        echo $gtVar;
        ?>
 = nullptr;
    if( queriesToRun.Overlaps(<?php 
        echo queryName($query);
        ?>
) ) {
        if( gtStates.IsThere(<?php 
        echo queryName($query);
        ?>
) ) {
            // Extract from container
            GLAPtr tState;
            GLAState& state = gtStates.Find(<?php 
        echo queryName($query);
        ?>
);
            tState.swap(state);

            // Check type
            FATALIF( tState.get_glaType() != <?php 
        echo $gt->cHash();
        ?>
,
                "Got different type than expected for GT of type <?php 
        echo $gt;
        ?>
");

            // Extract pointer
            <?php 
        echo $gtVar;
        ?>
 = (<?php 
        echo $gt;
        ?>
 *) tState.get_glaPtr();

            // Return container
            tState.swap(state);
        } // if we already have a state available
        else {
            // We don't have a state, create a new one
<?php 
        if ($gt->has_state()) {
            ?>

            // Extract the constant state, so we can use it to initialize
            // the GT
            const <?php 
            echo $gt->state();
            ?>
 * constState = nullptr;
            GLAPtr constStatePtr;

            // Extract from container
            FATALIF( !constStates.IsThere(<?php 
            echo queryName($query);
            ?>
),
                "No constant state found for query (<?php 
            echo queryName($query);
            ?>
) that requires a constant state");
            GLAState & tempState = constStates.Find(<?php 
            echo queryName($query);
            ?>
);
            constStatePtr.swap(tempState);

            // Check validity
            FATALIF( constStatePtr.get_glaType() != <?php 
            echo $gt->state()->cHash();
            ?>
,
                "Got different type than expected for constant state of type <?php 
            echo $gt->state();
            ?>
");

            // Get pointer
            constState = (const <?php 
            echo $gt->state();
            ?>
 *) constStatePtr.get_glaPtr();

            // Put back in container
            constStatePtr.swap(tempState);

<?php 
        }
        // if GT has a constant state
        ?>
            // Construct new GT
            <?php 
        echo $gtVar;
        ?>
 = new <?php 
        echo $gt;
        echo $cstStr;
        ?>
;

            // Play into container, so we can reuse it.
            GLAPtr newPtr( <?php 
        echo $gt->cHash();
        ?>
, <?php 
        echo $gtVar;
        ?>
 );
            QueryIDSet qry = <?php 
        echo queryName($query);
        ?>
;
            gtStates.Insert(qry, newPtr);
        } // if we had to create a state
    } // if query <?php 
        echo queryName($query);
        ?>
 is running

<?php 
    }
    // foreach query
    ?>

    // Prepare output bitstring iterator
    MMappedStorage queries_out_store;
    Column queries_out_col( queries_out_store );
    BStringIterator queries_out(queries_out_col, queriesCovered);

    // Prepare output for all passthrough attributes
<?php 
    cgConstructColumns($allPassthrough, '_out');
    ?>

    // Prepare output for synthesized attributes
<?php 
    cgConstructColumns($allSynth, '_out');
    ?>

    // Queries Covered by each passthrough attribute
<?php 
    foreach ($allPassthrough as $attr) {
        $type = $attr->type();
        $nullable = $type->is('nullable');
        $cstr = "";
        if ($nullable) {
            $cstr = "(GrokitNull::Value)";
        }
        ?>
    <?php 
        echo $type;
        ?>
 <?php 
        echo $attr->name();
        ?>
_out_default<?php 
        echo $cstr;
        ?>
;
    QueryIDSet <?php 
        echo $attr->name();
        ?>
_out_queries;
<?php 
        foreach ($queries as $query => $info) {
            if (in_array($attr, $info['pass'])) {
                ?>
    <?php 
                echo $attr->name();
                ?>
_out_queries.Union(<?php 
                echo queryName($query);
                ?>
);
<?php 
            }
            // if attribute is part of this query
        }
        // foreach query
    }
    // foreach passthrough attribute
    ?>

    // Queries covered by each synthesized attribute
<?php 
    foreach ($allSynth as $attr) {
        $type = $attr->type();
        $nullable = $type->is('nullable');
        $cstr = "";
        if ($nullable) {
            $cstr = "(GrokitNull::Value)";
        }
        ?>
    <?php 
        echo $type;
        ?>
 <?php 
        echo $attr->name();
        ?>
_out_default<?php 
        echo $cstr;
        ?>
;
    QueryIDSet <?php 
        echo $attr->name();
        ?>
_out_queries;
<?php 
        foreach ($queries as $query => $info) {
            if (in_array($attr, $info['output'])) {
                ?>
    <?php 
                echo $attr->name();
                ?>
_out_queries.Union(<?php 
                echo queryName($query);
                ?>
);
<?php 
            }
            // if attribute is part of this query
        }
        // foreach query
    }
    // foreach passthrough attribute
    ?>

    // Define constants used in expressions
<?php 
    foreach ($queries as $query => $info) {
        $input = $info['expressions'];
        cgDeclareConstants($input);
    }
    // foreach query
    ?>

    // Profiling information
    int64_t numTuplesIn = 0;
    int64_t numTuplesOut = 0;

#ifdef PER_QUERY_PROFILE
<?php 
    foreach ($queries as $query => $info) {
        ?>
    int64_t numTuplesIn_<?php 
        echo queryName($query);
        ?>
 = 0;
    int64_t numTuplesOut_<?php 
        echo queryName($query);
        ?>
 = 0;
<?php 
    }
    // foreach query
    ?>
#endif // PER_QUERY_PROFILE

    // Define should_iterate and is_done for each query
<?php 
    $iterVars = [];
    foreach ($queries as $query => $info) {
        $iterVar = 'should_process_' . queryName($query);
        $iterVars[] = $iterVar;
        ?>
    bool <?php 
        echo $iterVar;
        ?>
 = true;
<?php 
    }
    $iterExpr = implode(' || ', $iterVars);
    ?>

<?php 
    foreach ($queries as $query => $info) {
        // Call StartChunk() on iterable GTs
        $gt = $info['gt'];
        $gtVar = $gtVars[$query];
        if ($gt->iterable()) {
            ?>
    if (queriesToRun.Overlaps(<?php 
            echo queryName($query);
            ?>
)) {
        <?php 
            echo $gtVar;
            ?>
->StartChunk();
    }
<?php 
        }
    }
    ?>

    do {
<?php 
    cgAccessColumns($attMap, 'input', $wpName);
    ?>

    // Prepare input bitstring iterator
    BStringIterator queries_in;
    input.SwapBitmap(queries_in);
    
    numTuplesIn = 0;
#ifdef PER_QUERY_PROFILE
<?php 
    foreach ($queries as $query => $info) {
        ?>
    numTuplesIn_<?php 
        echo queryName($query);
        ?>
 = 0;
<?php 
    }
    // foreach query
    ?>
#endif // PER_QUERY_PROFILE

    // Begin processing tuples
    while( !queries_in.AtEndOfColumn() ) {
        numTuplesIn++;
        QueryIDSet qry = queries_in.GetCurrent();
        qry.Intersect(queriesToRun);
        queries_in.Advance();

<?php 
    cgAccessAttributes($attMap);
    foreach ($queries as $query => $info) {
        $gt = $info['gt'];
        $input = $info['expressions'];
        $output = $info['output'];
        $iterVar = 'should_process_' . queryName($query);
        $gtVar = $gtVars[$query];
        $outputVars = [];
        foreach ($output as $attr) {
            $outputVars[] = $attr->name() . '_out';
        }
        $inputVals = [];
        foreach ($input as $expr) {
            $inputVals[] = $expr->value();
        }
        // Prepare the output text
        ob_start();
        ?>
            // Insert synthesized attributes
<?php 
        foreach ($allSynth as $attr) {
            ?>
            if( queriesToRun.Overlaps(<?php 
            echo $attr->name();
            ?>
_out_queries) ) {
				<?php 
            echo $attr->name();
            ?>
_out_Column_Out.Insert(<?php 
            echo $attr->name();
            ?>
_out);
            }
			else {
				<?php 
            echo $attr->name();
            ?>
_out_Column_Out.Insert(<?php 
            echo $attr->name();
            ?>
_out_default);
			}
			<?php 
            echo $attr->name();
            ?>
_out_Column_Out.Advance();
<?php 
        }
        // foreach synthesized attribute
        ?>

            // Insert passthrough attributes
<?php 
        foreach ($allPassthrough as $attr) {
            ?>
            if( queriesToRun.Overlaps(<?php 
            echo $attr->name();
            ?>
_out_queries) ) {
                <?php 
            echo $attr->name();
            ?>
_out_Column_Out.Insert(<?php 
            echo $attr->name();
            ?>
);
            }
			else {
				<?php 
            echo $attr->name();
            ?>
_out_Column_Out.Insert(<?php 
            echo $attr->name();
            ?>
_out_default);
			}
			<?php 
            echo $attr->name();
            ?>
_out_Column_Out.Advance();
<?php 
        }
        // foreach synthesized attribute
        ?>

                queries_out.Insert(<?php 
        echo queryName($query);
        ?>
);
                queries_out.Advance();

                numTuplesOut++;
#ifdef PER_QUERY_PROFILE
                numTuplesOut_<?php 
        echo queryName($query);
        ?>
++;
#endif // PER_QUERY_PROFILE
<?php 
        $outputText = ob_get_clean();
        ?>
        // Do Query [<?php 
        echo queryName($query);
        ?>
]
        if( <?php 
        echo $iterVar;
        ?>
 && qry.Overlaps(<?php 
        echo queryName($query);
        ?>
) ) {
#ifdef PER_QUERY_PROFILE
            numTuplesIn_<?php 
        echo queryName($query);
        ?>
++;
#endif // PER_QUERY_PROFILE
<?php 
        cgDeclarePreprocessing($input, 3);
        ?>

<?php 
        if ($gt->result_type() == 'single') {
            ?>
            if( <?php 
            echo $gtVar;
            ?>
->ProcessTuple(<?php 
            echo implode(', ', $inputVals);
            ?>
, <?php 
            echo implode(', ', $outputVars);
            ?>
) ) {
<?php 
            echo $outputText;
            ?>

            } // if GT produced output for this tuple
<?php 
        } else {
            // if gt result type is single
            ?>
            <?php 
            echo $gtVar;
            ?>
->ProcessTuple(<?php 
            echo implode(', ', $inputVals);
            ?>
);

            while( <?php 
            echo $gtVar;
            ?>
->GetNextResult(<?php 
            echo implode(', ', $outputVars);
            ?>
) ) {
<?php 
            echo $outputText;
            ?>

            } // while GT has output for this tuple
<?php 
        }
        // if gt result type is multi
        ?>
        } // if <?php 
        echo queryName($query);
        ?>
 active in tuple

<?php 
    }
    // foreach query
    cgAdvanceAttributes($attMap, 2);
    ?>
    } // while we have tuples to process

<?php 
    foreach ($queries as $query => $info) {
        $gt = $info['gt'];
        $iterVar = 'should_process_' . queryName($query);
        $gtVar = $gtVars[$query];
        if ($gt->iterable()) {
            ?>
    if (<?php 
            echo $iterVar;
            ?>
) {
        <?php 
            echo $iterVar;
            ?>
 = <?php 
            echo $gtVar;
            ?>
->ShouldIterate();
    }

<?php 
        } else {
            ?>
    <?php 
            echo $iterVar;
            ?>
 = false;
<?php 
        }
    }
    //foreach query
    ?>

    // Put columns back into chunk
<?php 
    cgPutbackColumns($attMap, 'input', $wpName);
    ?>

    // Put bitmap back into chunk
    queries_in.Done();
    input.SwapBitmap(queries_in);

    } while(<?php 
    echo $iterExpr;
    ?>
);

    // Tell GTs that need to know about the chunk boundary
<?php 
    foreach ($queries as $query => $info) {
        $gt = $info['gt'];
        $gtVar = $gtVars[$query];
        if ($gt->chunk_boundary()) {
            ?>
    <?php 
            echo $gtVar;
            ?>
->ChunkBoundary();
<?php 
        }
        // if GT cares about chunk boundaries
    }
    // foreach query
    ?>



    // Finalize the output iterators and put the columns into the output chunk
    queries_out.Done();
    output.SwapBitmap(queries_out);

<?php 
    foreach ($allPassthrough as $attr) {
        ?>
    if( queriesToRun.Overlaps(<?php 
        echo $attr->name();
        ?>
_out_queries) ) {
        Column temp;
        <?php 
        echo $attr->name();
        ?>
_out_Column_Out.Done(temp);
        output.SwapColumn(temp, <?php 
        echo $attr->slot();
        ?>
);
    }
<?php 
    }
    // foreach passthrough attribute
    ?>

<?php 
    foreach ($allSynth as $attr) {
        ?>
    if( queriesToRun.Overlaps(<?php 
        echo $attr->name();
        ?>
_out_queries) ) {
        Column temp;
        <?php 
        echo $attr->name();
        ?>
_out_Column_Out.Done(temp);
        output.SwapColumn(temp, <?php 
        echo $attr->slot();
        ?>
);
    }
<?php 
    }
    // foreach passthrough attribute
    ?>

    PROFILING2_END;

    // Profiling
    PCounterList counterList;
    PCounter totalCntIn("tpi", numTuplesIn, "<?php 
    echo $wpName;
    ?>
");
    counterList.Append(totalCntIn);
    PCounter totalCntOut("tpo", numTuplesOut, "<?php 
    echo $wpName;
    ?>
");
    counterList.Append(totalCntOut);

#ifdef PER_QUERY_PROFILE
<?php 
    foreach ($queries as $query => $info) {
        ?>
    if( queriesToRun.Overlaps(<?php 
        echo queryName($query);
        ?>
) ) {
        PCounter cntIn("tpi <?php 
        echo queryName($query);
        ?>
", numTuplesIn_<?php 
        echo queryName($query);
        ?>
, "<?php 
        echo $wpName;
        ?>
");
        counterList.Append(cntIn);
        PCounter cntOut("tpo <?php 
        echo queryName($query);
        ?>
", numTuplesOut_<?php 
        echo queryName($query);
        ?>
, "<?php 
        echo $wpName;
        ?>
");
        counterList.Append(cntOut);
    }
<?php 
    }
    // foreach query
    ?>
#endif // PER_QUERY_PROFILE

    PROFILING2_SET(counterList, "<?php 
    echo $wpName;
    ?>
");

    // Return result and exit
    GTProcessChunkRez gtRez(gtStates, output);
    result.swap(gtRez);

    return WP_PROCESS_CHUNK;
}
//+{"kind":"WPF", "name":"Process Chunk", "action":"end"}
<?php 
}
Example #4
0
function GIGenerate($wpName, $type, $outputs, $constArgs, $tuples)
{
    // put an element in front to form constant arguments
    array_unshift($constArgs, "stream_info");
    $constArgsStr = join($constArgs, ',');
    // comma separated list of outputs
    $outputArgs = join(array_map(function ($el) {
        return $el->name();
    }, $outputs), ',');
    ?>


#include "Dictionary.h"
#include "DictionaryManager.h"
#include "GIStreamInfo.h"
#include "Profiling.h"
#include <iostream>

//+{"kind":"WPF", "name":"Produce Chunk", "action":"start"}
extern "C"
int GIProduceChunkWorkFunc_<?php 
    echo $wpName;
    ?>
 ( WorkDescription &workDescription, ExecEngineData &result) {
    const size_t maxTuplesPerChunk = <?php 
    echo $tuples == 0 ? "PREFERED_TUPLES_PER_CHUNK" : $tuples;
    ?>
;

    GIProduceChunkWD myWork;
    myWork.swap( workDescription );

    GLAState &gi_state = myWork.get_gi();
    GIStreamProxy &stream_info = myWork.get_stream_info();

    QueryIDSet queriesToRun = myWork.get_queriesCovered();

    GLAPtr state_ptr;
    state_ptr.swap(gi_state);

    <?php 
    echo $type->value();
    ?>
 * my_state = NULL;

    if( state_ptr.IsValid() ) {
        my_state = (<?php 
    echo $type->value();
    ?>
 *) state_ptr.get_glaPtr();
    } else {
        my_state = new <?php 
    echo $type->value();
    ?>
 ( <?php 
    echo $constArgsStr;
    ?>
 );
        GLAPtr newPtr(<?php 
    echo $type->cHash();
    ?>
, (void*) my_state);
        newPtr.swap(state_ptr);
    }

    state_ptr.swap(gi_state);

    // Output chunk
    Chunk chunk;

    PROFILING2_START;
    // Start new columns and allocate storage for them
<?php 
    cgConstructColumns($outputs);
    ?>

    size_t tuple_count = 0;
    bool stream_done = false;

    while( !stream_done && tuple_count < maxTuplesPerChunk ) {
        if( __builtin_expect( my_state->ProduceTuple( <?php 
    echo $outputArgs;
    ?>
 ), 1) ) {
            ++tuple_count;
<?php 
    foreach ($outputs as $att) {
        ?>
            <?php 
        echo $att->name();
        ?>
_Column_Out.Insert(<?php 
        echo $att->name();
        ?>
);
            <?php 
        echo $att->name();
        ?>
_Column_Out.Advance();
<?php 
    }
    ?>
        }
        else {
            stream_done = true;
        }
    }

    // Deal with PreDone() calls to release read locks
<?php 
    foreach ($outputs as $att) {
        if ($att->type()->reqDictionary()) {
            ?>
    <?php 
            echo $att->name();
            ?>
_Column_Out.PreDone();
    <?php 
        }
    }
    ?>

    // Finalize output columns and put them into the chunk.
<?php 
    foreach ($outputs as $att) {
        if ($att->type()->reqDictionary()) {
            ?>
    <?php 
            echo $att->name();
            ?>
_Column_Out.Done(<?php 
            echo $att->name();
            ?>
_Column_Ocol,
    my_state->get_dictionary_<?php 
            echo $att->type()->dictionary();
            ?>
());
    <?php 
        } else {
            ?>
    <?php 
            echo $att->name();
            ?>
_Column_Out.Done(<?php 
            echo $att->name();
            ?>
_Column_Ocol);
    <?php 
        }
        ?>
    {
        int cSlot = <?php 
        echo $att->slot();
        ?>
;

        FATALIF( ! <?php 
        echo $att->name();
        ?>
_Column_Ocol.IsValid(), "Column _A_ invalid when packing into chunk!");
        chunk.SwapColumn( <?php 
        echo $att->name();
        ?>
_Column_Ocol, cSlot );
    }
<?php 
    }
    ?>


    PROFILING2_END;
    PROFILING2_SINGLE("tpo", tuple_count, "<?php 
    echo $wpName;
    ?>
");

    MMappedStorage bitStore;
    Column outBitCol(bitStore);
    BStringIterator outQueries( outBitCol, queriesToRun, tuple_count );
    outQueries.Done();
    chunk.SwapBitmap(outQueries);

    ChunkContainer chunkCont(chunk);

    // pack the chunk, stream, and GI into the result and send it back
    GIProduceChunkRez tempResult( stream_info, gi_state, chunkCont );
    result.swap(tempResult);

    if( stream_done )
    {
        // Deallocate GI
        delete my_state;
        GLAState blankState;
        blankState.swap(gi_state);
        return 1;
    }
    else{
        return 0;
    }
}
//+{"kind":"WPF", "name":"Produce Chunk", "action":"end"}

<?php 
}
Example #5
0
function GISTGenerate_ProduceResults($wpName, $queries, $attMap)
{
    ?>

extern "C"
int GISTProduceResultsWorkFunc_<?php 
    echo $wpName;
    ?>
(WorkDescription &workDescription, ExecEngineData &result) {
    GISTProduceResultsWD myWork;
    myWork.swap(workDescription);

    // Inputs
    QueryExit& whichOne = myWork.get_whichOne();
    GLAState& gist = myWork.get_gist();

    int fragmentNo = myWork.get_fragmentNo();

    // Outputs
    Chunk output;

<?php 
    cgDeclareQueryIDs($queries);
    ?>

    QueryIDSet queriesToRun = whichOne.query;

    // Start columns for outputs
<?php 
    foreach ($queries as $query => $info) {
        $output = $info['output'];
        cgConstructColumns($output);
    }
    // foreach query
    ?>

    // Output bitstring
    MMappedStorage myStore;
    Column bitmapOut(myStore);
    BStringIterator myOutBStringIter (bitmapOut, queriesToRun);

    PROFILING2_START;
    int64_t numTuples = 0;

#ifdef PER_QUERY_PROFILE
<?php 
    foreach ($queries as $query => $info) {
        ?>
    int64_t numTuples_<?php 
        echo queryName($query);
        ?>
 = 0;
<?php 
    }
    // foreach query
    ?>
#endif // PER_QUERY_PROFILE

<?php 
    foreach ($queries as $query => $info) {
        $gist = $info['gist'];
        $output = $info['output'];
        $resType = $gist->result_type();
        $resType = get_first_value($resType, ['fragment', 'multi', 'single', 'state']);
        ?>
    if( whichOne.query == <?php 
        echo queryName($query);
        ?>
 ) {

        // Extract the GIST state
        GLAPtr gistPtr;
        gistPtr.swap(gist);

        FATALIF(gistPtr.get_glaType() != <?php 
        echo $gist->cHash();
        ?>
,
            "GIST producing results is of incorrect type for query <?php 
        echo queryName($query);
        ?>
");

        <?php 
        echo $gist;
        ?>
* state_<?php 
        echo queryName($query);
        ?>
 = (<?php 
        echo $gist;
        ?>
*) gistPtr.get_glaPtr();

<?php 
        switch ($resType) {
            case 'single':
                ?>
        {
            state_<?php 
                echo queryName($query);
                ?>
->GetResult(<?php 
                echo implode(', ', $output);
                ?>
);
<?php 
                break;
            case 'multi':
                ?>
        state_<?php 
                echo queryName($query);
                ?>
->Finalize();
        while (state_<?php 
                echo queryName($query);
                ?>
->GetNextResult(<?php 
                echo implode(', ', $output);
                ?>
)) {
<?php 
                break;
            case 'fragment':
                ?>
        <?php 
                echo $gist;
                ?>
::Iterator* iterator
            = state_<?php 
                echo queryName($query);
                ?>
->Finalize( fragmentNo );
        while( state_<?php 
                echo queryName($query);
                ?>
->GetNextResult( iterator, <?php 
                echo implode(', ', $output);
                ?>
) ) {
<?php 
                break;
            case 'state':
                reset($output);
                $att = current($output);
                // Output attribute
                ?>
        {
<?php 
                if ($gist->finalize_as_state()) {
                    ?>
            state_<?php 
                    echo queryName($query);
                    ?>
->FinalizeState();
<?php 
                }
                ?>
             <?php 
                echo $att;
                ?>
 = <?php 
                echo $att->type();
                ?>
( state_<?php 
                echo queryName($query);
                ?>
 );
<?php 
                break;
            default:
                grokit_error("Do not know how to deal with output type of GLA {$gist}::cGla [{$resType}]");
        }
        // matches switch
        ?>

            numTuples++;
#ifdef PER_QUERY_PROFILE
            numTuples_<?php 
        echo queryName($query);
        ?>
++;
#endif // PER_QUERY_PROFILE

            // Advance the columns
            myOutBStringIter.Insert(<?php 
        echo queryName($query);
        ?>
);
            myOutBStringIter.Advance();

<?php 
        foreach ($output as $att) {
            ?>
            <?php 
            echo $att;
            ?>
_Column_Out.Insert(<?php 
            echo $att;
            ?>
);
            <?php 
            echo $att;
            ?>
_Column_Out.Advance();
<?php 
        }
        ?>
        } // Matches block for column stuff.
<?php 
        if ($resType == 'fragment') {
            ?>
        // Delete the iterator;
        delete iterator;
<?php 
        }
        ?>
    } // Matches whichOne
<?php 
    }
    // matches foreach query
    ?>

    myOutBStringIter.Done();
    output.SwapBitmap(myOutBStringIter);

    // Write columns
<?php 
    foreach ($queries as $query => $info) {
        $gist = $info['gist'];
        $output = $info['output'];
        ?>
    if( whichOne.query == <?php 
        echo queryName($query);
        ?>
 ) {
<?php 
        foreach ($output as $att) {
            ?>
        Column col_<?php 
            echo $att;
            ?>
;
        <?php 
            echo $att;
            ?>
_Column_Out.Done(col_<?php 
            echo $att;
            ?>
);
        output.SwapColumn(col_<?php 
            echo $att;
            ?>
, <?php 
            echo $att->slot();
            ?>
);
<?php 
        }
        // foreach output att
        ?>
    } // Matches whichOne
<?php 
    }
    // foreach query
    ?>

    ChunkContainer tempResult(output);
    tempResult.swap(result);

    return WP_FINALIZE; // ProduceResults
}

<?php 
}