void TestMultiColumnIndex::evalResults(/*TODO:optionally specify the scenario etc.*/)
{
    // Evaluate all/some of the 'scenarios' and see if their various implementations
    // select the same pins (n.b. the point is that multi-column indexes are more complex
    // to maintain in the store, hence more error-prone, but logically should return
    // the same results as their join equivalent).
    // TODO: we could also add full-scan as a third validation point, like in testmultivarjoin.
    mLogger.out() << "Evaluating queries..." << std::endl;
    int iScen;
    Scenarios::iterator iS;
    for (iScen = 0, iS = mScenarios.begin(); mScenarios.end() != iS; iScen++, iS++)
    {
        if (iScen < pos_end_collection)
            proposeValues(*iS, true);
        else
            proposeValues(*iS, false);
        mLogger.out() << "  number of proposed values for scenario" << iScen << ": " << (*iS).mProposedVals.size() << std::endl;
        size_t const lNumValSeries = (*iS).mProposedVals.size() / (*iS).mDescr.size();
        for (size_t i = 0; i < lNumValSeries; i++)
        {
            mLogger.out() << "  evaluating scenario " << iScen << " with series of values " << i << std::endl;
            size_t const lValStart = i * (*iS).mDescr.size();
            #if 0
                for (size_t j = lValStart; j < lValStart + (*iS).mDescr.size(); j++)
                    MVTApp::output((*iS).mProposedVals[j], mLogger.out());
            #endif

            Value * const lV = &(*iS).mProposedVals[lValStart];
            TPIDs const lR1 = evalSingles((*iS), lV);
            TPIDs const lR2 = evalMulti((*iS), lV);
            mLogger.out() << "  selected " << lR1.size() << " in 'singles (aka join)' vs " << lR2.size() << " in 'multi-column'" << std::endl;
            TVERIFY2(lR1 == lR2, "Comparison between singles and multi failed!");
        }
    }
}
void extractScenarios(const std::string& script, Scenarios& scenarios) {
  int braceCounter = 0;
  Scenario scenario;
  std::vector<ScriptLine> lines = tokenizeInLines(script);

  std::for_each(lines.begin(), lines.end(),
                [&scenarios, &scenario, &braceCounter](ScriptLine& line) {
                  boost::trim(line.content);
                  if (isLine<CLOSE_SCENARIO>(line)) {
                    --braceCounter;
                  }
                  if (braceCounter == 1) {
                    scenario.push_back(line);
                  }
                  if (isLine<START_SCENARIO>(line)) {
                    ++braceCounter;
                  }
                  if (braceCounter == 0) {
                    if (!scenario.empty()) scenarios.push_back(scenario);
                    scenario.clear();
                  }

                });
}
int TestMultiColumnIndex::execute()
{
    if (!MVTApp::startStore())
        { TVERIFY2(0, "Could not start store, bailing out completely"); return 1; }
    mSession = MVTApp::startSession();
    MVTApp::mapURIs(mSession, "TestMultiColumnIndex.prop", sizeof(mProps) / sizeof(mProps[0]), mProps);

    // index from 10th in mProps is used to mapping mapVT
    ValueType vtarray[] = { VT_INT, VT_DOUBLE, VT_STRING, VT_DOUBLE}; //TODO: more basic types
    mapVT = vtarray;
    num_mapVT = sizeof(vtarray)/sizeof(vtarray[0]);
    pos_end_collection = 0;
    // Describe the logical multi-index 'families'.
    // Note:
    //   The test expands each of these logical definitions into
    //   1) a multi-parameter family, and
    //   2) a join between multiple single-parameter families
    {
        /*
        DescrFamily lF1("TestMultiColumnIndex.A");
        lF1.mDescr.push_back(DescrCondition(0, OP_IN));
        lF1.mDescr.push_back(DescrCondition(1, OP_GT));
        lF1.mDescr.push_back(DescrCondition(2, OP_IN));
        mScenarios.push_back(lF1); // Note: Copied.
        pos_end_collection = 0;
        
        DescrFamily lF2("TestMultiColumnIndex.B");
        lF2.mDescr.push_back(DescrCondition(0, OP_IN));
        lF2.mDescr.push_back(DescrCondition(1, OP_IN));
        mScenarios.push_back(lF2); // Note: Copied.
        
        DescrFamily lF3("TestMultiColumnIndex.C");
        lF3.mDescr.push_back(DescrCondition(0, OP_GT));
        lF3.mDescr.push_back(DescrCondition(1, OP_GT));
        mScenarios.push_back(lF3); // Note: Copied.
        */
        // IF4 ~ IF6 is used to index on many test basic types(not on collections)
        DescrFamily lF4("TestMultiColumnIndex.C");
        lF4.mDescr.push_back(DescrCondition(10, OP_LT));
        lF4.mDescr.push_back(DescrCondition(13, OP_GT));
        mScenarios.push_back(lF4); // Note: Copied.

        DescrFamily lF5("TestMultiColumnIndex.D");
        lF5.mDescr.push_back(DescrCondition(11, OP_LT));
        lF5.mDescr.push_back(DescrCondition(12, OP_LT));
        lF5.mDescr.push_back(DescrCondition(13, OP_IN));
        mScenarios.push_back(lF5); // Note: Copied.

        DescrFamily lF6("TestMultiColumnIndex.E");
        lF6.mDescr.push_back(DescrCondition(10, OP_IN));
        lF6.mDescr.push_back(DescrCondition(12, OP_GT));
        lF6.mDescr.push_back(DescrCondition(13, OP_GT));
        mScenarios.push_back(lF6); // Note: Copied.
    }
    // TODO: more scenarios...

    {
        // TODO:
        //   build+c[r]ud+evaluate in different order
        //   (e.g. build all at beginning, vs all at end, vs progressively)
        //   (e.g. evaluate only some results vs all results)

        // Build the corresponding store families.
        for (Scenarios::iterator iS = mScenarios.begin(); mScenarios.end() != iS; iS++)
            buildFamilies(*iS);

        // Create pins.
        // TODO: all CRUD, not just create...
        //createPins();
        createPins2();

        // Delete some pins
        deletePins();

        // Evaluate results.
        evalResults();

        //delete some PINs and evaluate results.
    }

    mSession->terminate();
    MVTApp::stopStore();
    return 0;
}