/**
   * Tests offset and limit clauses for query.
   *
   * @throws Exception If failed.
   */
  public void testOffsetLimit() throws Exception {
    IgniteCache<Integer, Integer> c =
        ignite(0).getOrCreateCache(cacheConfig("ints", true, Integer.class, Integer.class));

    try {
      List<Integer> res = new ArrayList<>();

      Random rnd = new GridRandom();

      for (int i = 0; i < 10; i++) {
        int val = rnd.nextInt(100);

        c.put(i, val);
        res.add(val);
      }

      Collections.sort(res);

      String qry = "select _val from Integer order by _val ";

      assertEqualsCollections(res, columnQuery(c, qry));
      assertEqualsCollections(res.subList(0, 0), columnQuery(c, qry + "limit ?", 0));
      assertEqualsCollections(res.subList(0, 3), columnQuery(c, qry + "limit ?", 3));
      assertEqualsCollections(res.subList(0, 9), columnQuery(c, qry + "limit ? offset ?", 9, 0));
      assertEqualsCollections(res.subList(3, 7), columnQuery(c, qry + "limit ? offset ?", 4, 3));
      assertEqualsCollections(res.subList(7, 9), columnQuery(c, qry + "limit ? offset ?", 2, 7));
      assertEqualsCollections(res.subList(8, 10), columnQuery(c, qry + "limit ? offset ?", 2, 8));
      assertEqualsCollections(res.subList(9, 10), columnQuery(c, qry + "limit ? offset ?", 1, 9));
      assertEqualsCollections(res.subList(10, 10), columnQuery(c, qry + "limit ? offset ?", 1, 10));
      assertEqualsCollections(
          res.subList(9, 10), columnQuery(c, qry + "limit ? offset abs(-(4 + ?))", 1, 5));
    } finally {
      c.destroy();
    }
  }
  /**
   * @param idx Column index.
   * @param rows Rows.
   * @return Column as list.
   */
  private static <X> List<X> column(int idx, List<List<?>> rows) {
    List<X> res = new ArrayList<>(rows.size());

    for (List<?> row : rows) res.add((X) row.get(idx));

    return res;
  }
  /**
   * @param key Key to add.
   * @param val Optional update value.
   * @param conflictTtl Conflict TTL (optional).
   * @param conflictExpireTime Conflict expire time (optional).
   * @param conflictVer Conflict version (optional).
   * @param primary If given key is primary on this mapping.
   */
  public void addUpdateEntry(
      KeyCacheObject key,
      @Nullable Object val,
      long conflictTtl,
      long conflictExpireTime,
      @Nullable GridCacheVersion conflictVer,
      boolean primary) {
    EntryProcessor<Object, Object, Object> entryProcessor = null;

    if (op == TRANSFORM) {
      assert val instanceof EntryProcessor : val;

      entryProcessor = (EntryProcessor<Object, Object, Object>) val;
    }

    assert val != null || op == DELETE;

    keys.add(key);

    if (entryProcessor != null) {
      if (entryProcessors == null) entryProcessors = new ArrayList<>();

      entryProcessors.add(entryProcessor);
    } else if (val != null) {
      assert val instanceof CacheObject : val;

      if (vals == null) vals = new ArrayList<>();

      vals.add((CacheObject) val);
    }

    hasPrimary |= primary;

    // In case there is no conflict, do not create the list.
    if (conflictVer != null) {
      if (conflictVers == null) {
        conflictVers = new ArrayList<>();

        for (int i = 0; i < keys.size() - 1; i++) conflictVers.add(null);
      }

      conflictVers.add(conflictVer);
    } else if (conflictVers != null) conflictVers.add(null);

    if (conflictTtl >= 0) {
      if (conflictTtls == null) {
        conflictTtls = new GridLongList(keys.size());

        for (int i = 0; i < keys.size() - 1; i++) conflictTtls.add(CU.TTL_NOT_CHANGED);
      }

      conflictTtls.add(conflictTtl);
    }

    if (conflictExpireTime >= 0) {
      if (conflictExpireTimes == null) {
        conflictExpireTimes = new GridLongList(keys.size());

        for (int i = 0; i < keys.size() - 1; i++) conflictExpireTimes.add(CU.EXPIRE_TIME_CALCULATE);
      }

      conflictExpireTimes.add(conflictExpireTime);
    }
  }