Example #1
0
    protected Result run() {
      getConnection().getCacheControl(null).flushSchemaCache();
      IntegerProperty monLimit = MondrianProperties.instance().ResultLimit;
      int oldLimit = monLimit.get();
      try {
        monLimit.set(this.resultLimit);
        Result result = executeQuery(query, con);

        // Check the number of positions on the last axis, which is
        // the ROWS axis in a 2 axis query.
        int numAxes = result.getAxes().length;
        Axis a = result.getAxes()[numAxes - 1];
        final int positionCount = a.getPositions().size();
        assertEquals(rowCount, positionCount);
        return result;
      } finally {
        monLimit.set(oldLimit);
      }
    }
Example #2
0
  /**
   * During MDX query parse and execution, checks that the query results (or does not result) in a
   * particular SQL statement being generated.
   *
   * <p>Parses and executes the MDX query once for each SQL pattern in the current dialect. If there
   * are multiple patterns, runs the MDX query multiple times, and expects to see each SQL statement
   * appear. If there are no patterns in this dialect, the test trivially succeeds.
   *
   * @param testContext non-default test context if required
   * @param mdxQuery MDX query
   * @param patterns Set of patterns
   * @param negative false to assert if SQL is generated; true to assert if SQL is NOT generated
   * @param bypassSchemaCache whether to grab a new connection and bypass the schema cache before
   *     parsing the MDX query
   * @param clearCache whether to clear cache before executing the MDX query
   */
  protected void assertQuerySqlOrNot(
      TestContext testContext,
      String mdxQuery,
      SqlPattern[] patterns,
      boolean negative,
      boolean bypassSchemaCache,
      boolean clearCache) {
    Connection connection = testContext.getConnection();

    mdxQuery = testContext.upgradeQuery(mdxQuery);

    // Run the test once for each pattern in this dialect.
    // (We could optimize and run it once, collecting multiple queries, and
    // comparing all queries at the end.)
    Dialect dialect = testContext.getDialect();
    Dialect.DatabaseProduct d = dialect.getDatabaseProduct();
    boolean patternFound = false;
    for (SqlPattern sqlPattern : patterns) {
      if (!sqlPattern.hasDatabaseProduct(d)) {
        // If the dialect is not one in the pattern set, skip the
        // test. If in the end no pattern is located, print a warning
        // message if required.
        continue;
      }

      patternFound = true;

      String sql = sqlPattern.getSql();
      String trigger = sqlPattern.getTriggerSql();

      sql = dialectize(d, sql);
      trigger = dialectize(d, trigger);

      // Create a dummy DataSource which will throw a 'bomb' if it is
      // asked to execute a particular SQL statement, but will otherwise
      // behave exactly the same as the current DataSource.
      RolapUtil.setHook(new TriggerHook(trigger));
      Bomb bomb = null;
      try {
        if (bypassSchemaCache) {
          connection = testContext.withSchemaPool(false).getConnection();
        }
        final Query query = connection.parseQuery(mdxQuery);
        if (clearCache) {
          clearCache((RolapCube) query.getCube());
        }
        final Result result = connection.execute(query);
        Util.discard(result);
        bomb = null;
      } catch (Bomb e) {
        bomb = e;
      } catch (RuntimeException e) {
        // Walk up the exception tree and see if the root cause
        // was a SQL bomb.
        bomb = Util.getMatchingCause(e, Bomb.class);
        if (bomb == null) {
          throw e;
        }
      } finally {
        RolapUtil.setHook(null);
      }
      if (negative) {
        if (bomb != null) {
          fail("forbidden query [" + sql + "] detected");
        }
      } else {
        if (bomb == null) {
          fail("expected query [" + sql + "] did not occur");
        }
        assertEquals(
            replaceQuotes(sql.replaceAll("\r\n", "\n")),
            replaceQuotes(bomb.sql.replaceAll("\r\n", "\n")));
      }
    }

    // Print warning message that no pattern was specified for the current
    // dialect.
    if (!patternFound) {
      String warnDialect = MondrianProperties.instance().WarnIfNoPatternForDialect.get();

      if (warnDialect.equals(d.toString())) {
        System.out.println(
            "[No expected SQL statements found for dialect \""
                + dialect.toString()
                + "\" and test not run]");
      }
    }
  }
Example #3
0
  /**
   * Runs a query twice, with native crossjoin optimization enabled and disabled. If both results
   * are equal,and both aggree with the expected result, it is considered correct.
   *
   * <p>Optionally the query can be run with fresh connection. This is useful if the test case sets
   * its certain mondrian properties, e.g. native properties like: mondrian.native.filter.enable
   *
   * @param resultLimit Maximum result size of all the MDX operations in this query. This might be
   *     hard to estimate as it is usually larger than the rowCount of the final result. Setting it
   *     to 0 will cause this limit to be ignored.
   * @param rowCount Number of rows returned. (That is, the number of positions on the last axis of
   *     the query.)
   * @param mdx Query
   * @param expectedResult Expected result string
   * @param freshConnection Whether fresh connection is required
   */
  protected void checkNative(
      int resultLimit, int rowCount, String mdx, String expectedResult, boolean freshConnection) {
    // Don't run the test if we're testing expression dependencies.
    // Expression dependencies cause spurious interval calls to
    // 'level.getMembers()' which create false negatives in this test.
    if (MondrianProperties.instance().TestExpDependencies.get() > 0) {
      return;
    }

    getConnection().getCacheControl(null).flushSchemaCache();
    try {
      Logger.getLogger(getClass()).debug("*** Native: " + mdx);
      boolean reuseConnection = !freshConnection;
      Connection con = getTestContext().withSchemaPool(reuseConnection).getConnection();
      RolapNativeRegistry reg = getRegistry(con);
      reg.useHardCache(true);
      TestListener listener = new TestListener();
      reg.setListener(listener);
      reg.setEnabled(true);
      TestCase c = new TestCase(con, resultLimit, rowCount, mdx);
      Result result = c.run();
      String nativeResult = TestContext.toString(result);
      if (!listener.isFoundEvaluator()) {
        fail("expected native execution of " + mdx);
      }
      if (!listener.isExecuteSql()) {
        fail("cache is empty: expected SQL query to be executed");
      }
      if (MondrianProperties.instance().EnableRolapCubeMemberCache.get()) {
        // run once more to make sure that the result comes from cache
        // now
        listener.setExecuteSql(false);
        c.run();
        if (listener.isExecuteSql()) {
          fail("expected result from cache when query runs twice");
        }
      }
      con.close();

      Logger.getLogger(getClass()).debug("*** Interpreter: " + mdx);

      getConnection().getCacheControl(null).flushSchemaCache();
      con = getTestContext().withSchemaPool(false).getConnection();
      reg = getRegistry(con);
      listener.setFoundEvaluator(false);
      reg.setListener(listener);
      // disable RolapNativeSet
      reg.setEnabled(false);
      result = executeQuery(mdx, con);
      String interpretedResult = TestContext.toString(result);
      if (listener.isFoundEvaluator()) {
        fail("did not expect native executions of " + mdx);
      }

      if (expectedResult != null) {
        TestContext.assertEqualsVerbose(
            expectedResult,
            nativeResult,
            false,
            "Native implementation returned different result than " + "expected; MDX=" + mdx);
        TestContext.assertEqualsVerbose(
            expectedResult,
            interpretedResult,
            false,
            "Interpreter implementation returned different result than " + "expected; MDX=" + mdx);
      }

      if (!nativeResult.equals(interpretedResult)) {
        TestContext.assertEqualsVerbose(
            interpretedResult,
            nativeResult,
            false,
            "Native implementation returned different result than " + "interpreter; MDX=" + mdx);
      }
    } finally {
      Connection con = getConnection();
      RolapNativeRegistry reg = getRegistry(con);
      reg.setEnabled(true);
      reg.useHardCache(false);
    }
  }
Example #4
0
  /**
   * Checks that a given sequence of cell requests results in a particular SQL statement being
   * generated.
   *
   * <p>Always clears the cache before running the requests.
   *
   * <p>Runs the requests once for each SQL pattern in the current dialect. If there are multiple
   * patterns, runs the MDX query multiple times, and expects to see each SQL statement appear. If
   * there are no patterns in this dialect, the test trivially succeeds.
   *
   * @param requests Sequence of cell requests
   * @param patterns Set of patterns
   * @param negative Set to false in order to 'expect' a query or true to 'forbid' a query.
   */
  protected void assertRequestSql(CellRequest[] requests, SqlPattern[] patterns, boolean negative) {
    final RolapStar star = requests[0].getMeasure().getStar();
    final String cubeName = requests[0].getMeasure().getCubeName();
    final RolapCube cube = lookupCube(cubeName);
    final Dialect sqlDialect = star.getSqlQueryDialect();
    Dialect.DatabaseProduct d = sqlDialect.getDatabaseProduct();
    SqlPattern sqlPattern = SqlPattern.getPattern(d, patterns);
    if (d == Dialect.DatabaseProduct.UNKNOWN) {
      // If the dialect is not one in the pattern set, do not run the
      // test. We do not print any warning message.
      return;
    }

    boolean patternFound = false;
    for (SqlPattern pattern : patterns) {
      if (!pattern.hasDatabaseProduct(d)) {
        continue;
      }

      patternFound = true;

      clearCache(cube);

      String sql = sqlPattern.getSql();
      String trigger = sqlPattern.getTriggerSql();
      switch (d) {
        case ORACLE:
          sql = sql.replaceAll(" =as= ", " ");
          trigger = trigger.replaceAll(" =as= ", " ");
          break;
        case TERADATA:
          sql = sql.replaceAll(" =as= ", " as ");
          trigger = trigger.replaceAll(" =as= ", " as ");
          break;
      }

      // Create a dummy DataSource which will throw a 'bomb' if it is
      // asked to execute a particular SQL statement, but will otherwise
      // behave exactly the same as the current DataSource.
      RolapUtil.setHook(new TriggerHook(trigger));
      Bomb bomb;
      final Execution execution =
          new Execution(((RolapConnection) getConnection()).getInternalStatement(), 1000);
      final AggregationManager aggMgr =
          execution
              .getMondrianStatement()
              .getMondrianConnection()
              .getServer()
              .getAggregationManager();
      final Locus locus = new Locus(execution, "BatchTestCase", "BatchTestCase");
      try {
        FastBatchingCellReader fbcr =
            new FastBatchingCellReader(execution, getCube(cubeName), aggMgr);
        for (CellRequest request : requests) {
          fbcr.recordCellRequest(request);
        }
        // The FBCR will presume there is a current Locus in the stack,
        // so let's create a mock one.
        Locus.push(locus);
        fbcr.loadAggregations();
        bomb = null;
      } catch (Bomb e) {
        bomb = e;
      } finally {
        RolapUtil.setHook(null);
        Locus.pop(locus);
      }
      if (!negative && bomb == null) {
        fail("expected query [" + sql + "] did not occur");
      } else if (negative && bomb != null) {
        fail("forbidden query [" + sql + "] detected");
      }
      TestContext.assertEqualsVerbose(replaceQuotes(sql), replaceQuotes(bomb.sql));
    }

    // Print warning message that no pattern was specified for the current
    // dialect.
    if (!patternFound) {
      String warnDialect = MondrianProperties.instance().WarnIfNoPatternForDialect.get();

      if (warnDialect.equals(d.toString())) {
        System.out.println(
            "[No expected SQL statements found for dialect \""
                + sqlDialect.toString()
                + "\" and test not run]");
      }
    }
  }