@Test
  public void testNestedAndCollectionPdx() throws CacheException {

    final Host host = Host.getHost(0);
    VM vm0 = host.getVM(0);
    VM vm1 = host.getVM(1);
    VM vm2 = host.getVM(2);
    VM vm3 = host.getVM(3);
    final int numberOfEntries = 50;

    final String[] queries = new String[] {
        "SELECT * FROM " + regName + " pf where pf.position1.secId > '2'",
        "SELECT * FROM " + regName + " p where p.position3[1].portfolioId = 2",
        "SELECT * FROM " + regName + " p, p.positions.values AS pos WHERE pos.secId != '1'",
        "SELECT key, positions FROM " + regName + ".entrySet, value.positions.values "
            + "positions WHERE positions.mktValue >= 25.00",
        "SELECT * FROM " + regName + " portfolio1, " + regName2 + " portfolio2 WHERE "
            + "portfolio1.status = portfolio2.status",
        "SELECT portfolio1.ID, portfolio2.status FROM " + regName + " portfolio1, "
            + regName + " portfolio2  WHERE portfolio1.status = portfolio2.status",
        "SELECT * FROM " + regName + " portfolio1, portfolio1.positions.values positions1, "
            + regName + " portfolio2,  portfolio2.positions.values positions2 WHERE "
            + "positions1.secId = positions2.secId ",
        "SELECT * FROM " + regName + " portfolio, portfolio.positions.values positions WHERE "
            + "portfolio.Pk IN SET ('1', '2') AND positions.secId = '1'",
        "SELECT DISTINCT * FROM " + regName + "  pf1, pf1.collectionHolderMap.values coll1,"
            + " pf1.positions.values posit1, " + regName2
            + "  pf2, pf2.collectionHolderMap.values "
            + " coll2, pf2.positions.values posit2 WHERE posit1.secId='IBM' AND posit2.secId='IBM'",};

    // Start server1
    vm0.invoke(new CacheSerializableRunnable("Create cache server") {
      @Override
      public void run2() throws CacheException {
        configAndStartBridgeServer();
        Region region1 = getRootRegion().getSubregion(regionName);
        Region region2 = getRootRegion().getSubregion(regionName2);

        for (int i = 0; i < numberOfEntries; i++) {
          region1.put("key-" + i, new PortfolioPdx(i, i));
          region2.put("key-" + i, new PortfolioPdx(i, i));
        }
      }
    });

    // Start server2
    vm1.invoke(new CacheSerializableRunnable("Create cache server") {
      @Override
      public void run2() throws CacheException {
        configAndStartBridgeServer();
        Region region = getRootRegion().getSubregion(regionName);
        Region region2 = getRootRegion().getSubregion(regionName2);
      }
    });


    // Client pool.
    final int port0 = vm0.invoke(PdxQueryDUnitTest::getCacheServerPort);
    final int port1 = vm1.invoke(PdxQueryDUnitTest::getCacheServerPort);

    final String host0 = NetworkUtils.getServerHostName(vm0.getHost());

    // Create client pool.
    final String poolName = "testClientServerQueryPool";
    createPool(vm2, poolName, new String[] {host0}, new int[] {port0}, true);
    createPool(vm3, poolName, new String[] {host0}, new int[] {port1}, true);

    // Create client region
    vm3.invoke(new CacheSerializableRunnable("Create region") {
      @Override
      public void run2() throws CacheException {

        AttributesFactory factory = new AttributesFactory();
        factory.setScope(Scope.LOCAL);
        ClientServerTestCase.configureConnectionPool(factory, host0, port1, -1, true, -1, -1, null);
        Region region1 = createRegion(regionName, rootRegionName, factory.create());
        Region region2 = createRegion(regionName2, rootRegionName, factory.create());

        for (int i = 0; i < numberOfEntries; i++) {
          region1.put("key-" + i, new PortfolioPdx(i, i));
          region2.put("key-" + i, new PortfolioPdx(i, i));
        }
      }
    });

    // Execute client queries
    SerializableRunnable executeQueries = new CacheSerializableRunnable("Execute queries") {
      @Override
      public void run2() throws CacheException {
        QueryService remoteQueryService = null;
        QueryService localQueryService = null;
        SelectResults[][] rs = new SelectResults[1][2];
        try {
          remoteQueryService = (PoolManager.find(poolName)).getQueryService();
          localQueryService = getCache().getQueryService();
        } catch (Exception e) {
          Assert.fail("Failed to get QueryService.", e);
        }

        for (final String s : queries) {
          try {
            logger.info("### Executing Query on server:" + s);
            Query query = remoteQueryService.newQuery(s);
            rs[0][0] = (SelectResults) query.execute();

            logger.info("### Executing Query locally:" + s);
            query = localQueryService.newQuery(s);
            rs[0][1] = (SelectResults) query.execute();

            // Compare local and remote query results.
            if (!CacheUtils.compareResultsOfWithAndWithoutIndex(rs)) {
              fail("Local and Remote Query Results are not matching for query :" + s);
            }

          } catch (Exception e) {
            Assert.fail("Failed executing " + s, e);
          }

        }
      }
    };

    vm3.invoke(executeQueries);

    vm1.invoke(new CacheSerializableRunnable("Create cache server") {
      @Override
      public void run2() throws CacheException {
        assertEquals(0, PortfolioPdx.numInstance);
        assertEquals(0, PositionPdx.numInstance);
      }
    });


    // Create index
    vm1.invoke(new CacheSerializableRunnable("Create cache server") {
      @Override
      public void run2() throws CacheException {
        Region region = getRootRegion().getSubregion(regionName);
        QueryService qs = getCache().getQueryService();
        try {
          qs.createIndex("pkIndex", IndexType.FUNCTIONAL, "portfolio.Pk", regName + " portfolio");
          qs.createIndex("secIdIndex", IndexType.FUNCTIONAL, "pos.secId",
              regName + " p, p.positions.values AS pos");
          qs.createIndex("tickerIndex", IndexType.FUNCTIONAL, "pf.position1.secId",
              regName + " pf");
          qs.createIndex("secIdIndexPf1", IndexType.FUNCTIONAL, "pos11.secId",
              regName + " pf1, pf1.collectionHolderMap.values coll1, pf1.positions.values pos11");
          qs.createIndex("secIdIndexPf2", IndexType.FUNCTIONAL, "pos22.secId",
              regName2 + " pf2, pf2.collectionHolderMap.values coll2, pf2.positions.values pos22");
        } catch (Exception ex) {
          fail("Unable to create index. " + ex.getMessage());
        }
      }
    });

    vm3.invoke(executeQueries);

    // index is created on portfolio.Pk field which does not exists in
    // PorfolioPdx object
    // but there is a method getPk(), so for #44436, the objects are
    // deserialized to get the value in vm1
    vm1.invoke(new CacheSerializableRunnable("Create cache server") {
      @Override
      public void run2() throws CacheException {
        assertEquals(numberOfEntries, PortfolioPdx.numInstance);
        assertEquals(325, PositionPdx.numInstance); // 50 PorforlioPdx objects
        // create (50*3)+50+50+50+25
        // = 325 PositionPdx objects
        // when deserialized
      }
    });

    closeClient(vm2);
    closeClient(vm3);
    closeClient(vm1);
    closeClient(vm0);
  }
Tests client-server query with nested and collection of Pdx.
geode-core/src/distributedTest/java/org/apache/geode/cache/query/dunit/PdxQueryDUnitTest.java