Java Code Examples for org.apache.calcite.plan.hep.HepPlanner#setRoot()
The following examples show how to use
org.apache.calcite.plan.hep.HepPlanner#setRoot() .
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example 1
Source File: HepPlannerTest.java From calcite with Apache License 2.0 | 6 votes |
/** Tests that if two relational expressions are equivalent, the planner * notices, and only applies the rule once. */ @Test void testCommonSubExpression() { // In the following, // (select 1 from dept where abs(-1)=20) // occurs twice, but it's a common sub-expression, so the rule should only // apply once. HepProgramBuilder programBuilder = HepProgram.builder(); programBuilder.addRuleInstance(FilterToCalcRule.INSTANCE); final HepTestListener listener = new HepTestListener(0); HepPlanner planner = new HepPlanner(programBuilder.build()); planner.addListener(listener); final String sql = "(select 1 from dept where abs(-1)=20)\n" + "union all\n" + "(select 1 from dept where abs(-1)=20)"; planner.setRoot(tester.convertSqlToRel(sql).rel); RelNode bestRel = planner.findBestExp(); assertThat(bestRel.getInput(0).equals(bestRel.getInput(1)), is(true)); assertThat(listener.getApplyTimes() == 1, is(true)); }
Example 2
Source File: SqlHintsConverterTest.java From calcite with Apache License 2.0 | 6 votes |
@Test void testHintsPropagationInHepPlannerRules() { final String sql = "select /*+ use_hash_join(r, s), use_hash_join(emp, dept) */\n" + "ename, job, sal, dept.name\n" + "from emp join dept on emp.deptno = dept.deptno"; final RelNode rel = tester.convertSqlToRel(sql).rel; final RelHint hint = RelHint.builder("USE_HASH_JOIN") .inheritPath(0) .hintOption("EMP") .hintOption("DEPT") .build(); // Validate Hep planner. HepProgram program = new HepProgramBuilder() .addRuleInstance(MockJoinRule.INSTANCE) .build(); HepPlanner planner = new HepPlanner(program); planner.setRoot(rel); RelNode newRel = planner.findBestExp(); new ValidateHintVisitor(hint, Join.class).go(newRel); }
Example 3
Source File: Programs.java From Bats with Apache License 2.0 | 6 votes |
/** Creates a program that executes a {@link HepProgram}. */ public static Program of(final HepProgram hepProgram, final boolean noDag, final RelMetadataProvider metadataProvider) { return (planner, rel, requiredOutputTraits, materializations, lattices) -> { final HepPlanner hepPlanner = new HepPlanner(hepProgram, null, noDag, null, RelOptCostImpl.FACTORY); List<RelMetadataProvider> list = new ArrayList<>(); if (metadataProvider != null) { list.add(metadataProvider); } hepPlanner.registerMetadataProviders(list); RelMetadataProvider plannerChain = ChainedRelMetadataProvider.of(list); rel.getCluster().setMetadataProvider(plannerChain); hepPlanner.setRoot(rel); return hepPlanner.findBestExp(); }; }
Example 4
Source File: HepPlannerTest.java From calcite with Apache License 2.0 | 6 votes |
@Test void testGC() throws Exception { HepProgramBuilder programBuilder = HepProgram.builder(); programBuilder.addMatchOrder(HepMatchOrder.TOP_DOWN); programBuilder.addRuleInstance(CalcMergeRule.INSTANCE); programBuilder.addRuleInstance(ProjectToCalcRule.INSTANCE); programBuilder.addRuleInstance(FilterToCalcRule.INSTANCE); HepPlanner planner = new HepPlanner(programBuilder.build()); planner.setRoot( tester.convertSqlToRel("select upper(name) from dept where deptno=20").rel); planner.findBestExp(); // Reuse of HepPlanner (should trigger GC). planner.setRoot( tester.convertSqlToRel("select upper(name) from dept where deptno=20").rel); planner.findBestExp(); }
Example 5
Source File: RelDecorrelator.java From calcite with Apache License 2.0 | 5 votes |
public RelNode removeCorrelationViaRule(RelNode root) { final RelBuilderFactory f = relBuilderFactory(); HepProgram program = HepProgram.builder() .addRuleInstance(new RemoveSingleAggregateRule(f)) .addRuleInstance(new RemoveCorrelationForScalarProjectRule(f)) .addRuleInstance(new RemoveCorrelationForScalarAggregateRule(f)) .build(); HepPlanner planner = createPlanner(program); planner.setRoot(root); return planner.findBestExp(); }
Example 6
Source File: MaterializedViewFilterScanRule.java From quark with Apache License 2.0 | 5 votes |
protected void apply(RelOptRuleCall call, Filter filter, TableScan scan) { //Avoid optimizing already optimized scan if (scan instanceof QuarkViewScan || scan instanceof QuarkTileScan) { return; } RelNode root = filter.copy(filter.getTraitSet(), Collections.singletonList((RelNode) scan)); RelOptPlanner planner = call.getPlanner(); if (planner instanceof VolcanoPlanner) { List<RelOptMaterialization> materializations = ((VolcanoPlanner) planner).getMaterializations(); for (RelOptMaterialization materialization : materializations) { if (scan.getRowType().equals(materialization.queryRel.getRowType())) { RelNode target = materialization.queryRel; final HepPlanner hepPlanner = new HepPlanner(program, planner.getContext()); hepPlanner.setRoot(target); target = hepPlanner.findBestExp(); List<RelNode> subs = new MaterializedViewSubstitutionVisitor(target, root) .go(materialization.tableRel); for (RelNode s : subs) { call.transformTo(s); } } } } }
Example 7
Source File: MaterializationExpander.java From dremio-oss with Apache License 2.0 | 5 votes |
private static RelNode applyRule(RelNode node, RelOptRule rule) { final HepProgramBuilder builder = HepProgram.builder(); builder.addMatchOrder(HepMatchOrder.ARBITRARY); builder.addRuleCollection(ImmutableList.of(rule)); final HepProgram program = builder.build(); final HepPlanner planner = new HepPlanner(program); planner.setRoot(node); return planner.findBestExp(); }
Example 8
Source File: SqlHintsConverterTest.java From calcite with Apache License 2.0 | 5 votes |
@Test void testHintsForCalc() { final String sql = "select /*+ resource(mem='1024MB')*/ ename, sal, deptno from emp"; final RelNode rel = tester.convertSqlToRel(sql).rel; final RelHint hint = RelHint.builder("RESOURCE") .hintOption("MEM", "1024MB") .build(); // planner rule to convert Project to Calc. HepProgram program = new HepProgramBuilder() .addRuleInstance(ProjectToCalcRule.INSTANCE) .build(); HepPlanner planner = new HepPlanner(program); planner.setRoot(rel); RelNode newRel = planner.findBestExp(); new ValidateHintVisitor(hint, Calc.class).go(newRel); }
Example 9
Source File: MycatCalcitePlanner.java From Mycat2 with GNU General Public License v3.0 | 5 votes |
public RelNode pullUpUnion(RelNode relNode1) { HepProgramBuilder hepProgramBuilder = new HepProgramBuilder(); hepProgramBuilder.addMatchLimit(PULL_RULES.size()); hepProgramBuilder.addRuleCollection(PULL_RULES); final HepPlanner planner2 = new HepPlanner(hepProgramBuilder.build()); planner2.setRoot(relNode1); return planner2.findBestExp(); }
Example 10
Source File: RelDecorrelator.java From flink with Apache License 2.0 | 5 votes |
public RelNode removeCorrelationViaRule(RelNode root) { final RelBuilderFactory f = relBuilderFactory(); HepProgram program = HepProgram.builder() .addRuleInstance(new RemoveSingleAggregateRule(f)) .addRuleInstance(new RemoveCorrelationForScalarProjectRule(f)) .addRuleInstance(new RemoveCorrelationForScalarAggregateRule(f)) .build(); HepPlanner planner = createPlanner(program); planner.setRoot(root); return planner.findBestExp(); }
Example 11
Source File: Interpreter.java From calcite with Apache License 2.0 | 5 votes |
private RelNode optimize(RelNode rootRel) { final HepProgram hepProgram = new HepProgramBuilder() .addRuleInstance(CalcSplitRule.INSTANCE) .addRuleInstance(FilterTableScanRule.INSTANCE) .addRuleInstance(FilterTableScanRule.INTERPRETER) .addRuleInstance(ProjectTableScanRule.INSTANCE) .addRuleInstance(ProjectTableScanRule.INTERPRETER) .addRuleInstance(AggregateReduceFunctionsRule.INSTANCE) .build(); final HepPlanner planner = new HepPlanner(hepProgram); planner.setRoot(rootRel); rootRel = planner.findBestExp(); return rootRel; }
Example 12
Source File: RelDecorrelator.java From Bats with Apache License 2.0 | 5 votes |
public RelNode removeCorrelationViaRule(RelNode root) { final RelBuilderFactory f = relBuilderFactory(); HepProgram program = HepProgram.builder().addRuleInstance(new RemoveSingleAggregateRule(f)) .addRuleInstance(new RemoveCorrelationForScalarProjectRule(f)) .addRuleInstance(new RemoveCorrelationForScalarAggregateRule(f)).build(); HepPlanner planner = createPlanner(program); planner.setRoot(root); return planner.findBestExp(); }
Example 13
Source File: RelDecorrelator.java From Bats with Apache License 2.0 | 5 votes |
private RelNode decorrelate(RelNode root) { // first adjust count() expression if any final RelBuilderFactory f = relBuilderFactory(); HepProgram program = HepProgram.builder().addRuleInstance(new AdjustProjectForCountAggregateRule(false, f)) .addRuleInstance(new AdjustProjectForCountAggregateRule(true, f)) .addRuleInstance(new FilterJoinRule.FilterIntoJoinRule(true, f, FilterJoinRule.TRUE_PREDICATE)) .addRuleInstance(new FilterProjectTransposeRule(Filter.class, Project.class, true, true, f)) .addRuleInstance(new FilterCorrelateRule(f)).build(); HepPlanner planner = createPlanner(program); planner.setRoot(root); root = planner.findBestExp(); // Perform decorrelation. map.clear(); final Frame frame = getInvoke(root, null); if (frame != null) { // has been rewritten; apply rules post-decorrelation final HepProgram program2 = HepProgram.builder() .addRuleInstance(new FilterJoinRule.FilterIntoJoinRule(true, f, FilterJoinRule.TRUE_PREDICATE)) .addRuleInstance(new FilterJoinRule.JoinConditionPushRule(f, FilterJoinRule.TRUE_PREDICATE)) .build(); final HepPlanner planner2 = createPlanner(program2); final RelNode newRoot = frame.r; planner2.setRoot(newRoot); return planner2.findBestExp(); } return root; }
Example 14
Source File: InterpreterTest.java From calcite with Apache License 2.0 | 5 votes |
@Test void testInterpretSemiJoin() throws Exception { final String sql = "select x, y from (values (1, 'a'), (2, 'b'), (3, 'c')) as t(x, y)\n" + "where x in\n" + "(select x from (values (1, 'd'), (3, 'g')) as t2(x, y))"; SqlNode validate = planner.validate(planner.parse(sql)); RelNode convert = planner.rel(validate).rel; final HepProgram program = new HepProgramBuilder() .addRuleInstance(SemiJoinRule.PROJECT) .build(); final HepPlanner hepPlanner = new HepPlanner(program); hepPlanner.setRoot(convert); final RelNode relNode = hepPlanner.findBestExp(); final Interpreter interpreter = new Interpreter(dataContext, relNode); assertRows(interpreter, true, "[1, a]", "[3, c]"); }
Example 15
Source File: RelOptMaterializations.java From calcite with Apache License 2.0 | 4 votes |
private static List<RelNode> substitute( RelNode root, RelOptMaterialization materialization) { // First, if the materialization is in terms of a star table, rewrite // the query in terms of the star table. if (materialization.starTable != null) { RelNode newRoot = RelOptMaterialization.tryUseStar(root, materialization.starRelOptTable); if (newRoot != null) { root = newRoot; } } // Push filters to the bottom, and combine projects on top. RelNode target = materialization.queryRel; // try to trim unused field in relational expressions. root = trimUnusedfields(root); target = trimUnusedfields(target); HepProgram program = new HepProgramBuilder() .addRuleInstance(FilterProjectTransposeRule.INSTANCE) .addRuleInstance(FilterMergeRule.INSTANCE) .addRuleInstance(FilterJoinRule.FILTER_ON_JOIN) .addRuleInstance(FilterJoinRule.JOIN) .addRuleInstance(FilterAggregateTransposeRule.INSTANCE) .addRuleInstance(ProjectMergeRule.INSTANCE) .addRuleInstance(ProjectRemoveRule.INSTANCE) .addRuleInstance(ProjectJoinTransposeRule.INSTANCE) .addRuleInstance(ProjectSetOpTransposeRule.INSTANCE) .addRuleInstance(FilterToCalcRule.INSTANCE) .addRuleInstance(ProjectToCalcRule.INSTANCE) .addRuleInstance(FilterCalcMergeRule.INSTANCE) .addRuleInstance(ProjectCalcMergeRule.INSTANCE) .addRuleInstance(CalcMergeRule.INSTANCE) .build(); // We must use the same HEP planner for the two optimizations below. // Thus different nodes with the same digest will share the same vertex in // the plan graph. This is important for the matching process. final HepPlanner hepPlanner = new HepPlanner(program); hepPlanner.setRoot(target); target = hepPlanner.findBestExp(); hepPlanner.setRoot(root); root = hepPlanner.findBestExp(); return new SubstitutionVisitor(target, root).go(materialization.tableRel); }
Example 16
Source File: RelDecorrelator.java From flink with Apache License 2.0 | 4 votes |
private RelNode decorrelate(RelNode root) { // first adjust count() expression if any final RelBuilderFactory f = relBuilderFactory(); HepProgram program = HepProgram.builder() .addRuleInstance(new AdjustProjectForCountAggregateRule(false, f)) .addRuleInstance(new AdjustProjectForCountAggregateRule(true, f)) .addRuleInstance( // use FilterJoinRule instead of FlinkFilterJoinRule while CALCITE-3170 is fixed new FlinkFilterJoinRule.FlinkFilterIntoJoinRule(true, f, FlinkFilterJoinRule.TRUE_PREDICATE)) .addRuleInstance( new FilterProjectTransposeRule(Filter.class, Project.class, true, true, f)) .addRuleInstance(new FilterCorrelateRule(f)) .build(); HepPlanner planner = createPlanner(program); planner.setRoot(root); root = planner.findBestExp(); // Perform decorrelation. map.clear(); final Frame frame = getInvoke(root, null); if (frame != null) { // has been rewritten; apply rules post-decorrelation final HepProgram program2 = HepProgram.builder() .addRuleInstance( // use FilterJoinRule instead of FlinkFilterJoinRule while CALCITE-3170 is fixed new FlinkFilterJoinRule.FlinkFilterIntoJoinRule( true, f, FlinkFilterJoinRule.TRUE_PREDICATE)) .addRuleInstance( new FlinkFilterJoinRule.FlinkJoinConditionPushRule( f, FlinkFilterJoinRule.TRUE_PREDICATE)) .build(); final HepPlanner planner2 = createPlanner(program2); final RelNode newRoot = frame.r; planner2.setRoot(newRoot); return planner2.findBestExp(); } return root; }
Example 17
Source File: MaterializedViewJoinRule.java From calcite with Apache License 2.0 | 4 votes |
@Override protected RelNode rewriteQuery( RelBuilder relBuilder, RexBuilder rexBuilder, RexSimplify simplify, RelMetadataQuery mq, RexNode compensationColumnsEquiPred, RexNode otherCompensationPred, Project topProject, RelNode node, BiMap<RelTableRef, RelTableRef> viewToQueryTableMapping, EquivalenceClasses viewEC, EquivalenceClasses queryEC) { // Our target node is the node below the root, which should have the maximum // number of available expressions in the tree in order to maximize our // number of rewritings. // We create a project on top. If the program is available, we execute // it to maximize rewriting opportunities. For instance, a program might // pull up all the expressions that are below the aggregate so we can // introduce compensation filters easily. This is important depending on // the planner strategy. RelNode newNode = node; RelNode target = node; if (unionRewritingPullProgram != null) { final HepPlanner tmpPlanner = new HepPlanner(unionRewritingPullProgram); tmpPlanner.setRoot(newNode); newNode = tmpPlanner.findBestExp(); target = newNode.getInput(0); } // All columns required by compensating predicates must be contained // in the query. List<RexNode> queryExprs = extractReferences(rexBuilder, target); if (!compensationColumnsEquiPred.isAlwaysTrue()) { compensationColumnsEquiPred = rewriteExpression(rexBuilder, mq, target, target, queryExprs, viewToQueryTableMapping.inverse(), queryEC, false, compensationColumnsEquiPred); if (compensationColumnsEquiPred == null) { // Skip it return null; } } // For the rest, we use the query equivalence classes if (!otherCompensationPred.isAlwaysTrue()) { otherCompensationPred = rewriteExpression(rexBuilder, mq, target, target, queryExprs, viewToQueryTableMapping.inverse(), viewEC, true, otherCompensationPred); if (otherCompensationPred == null) { // Skip it return null; } } final RexNode queryCompensationPred = RexUtil.not( RexUtil.composeConjunction(rexBuilder, ImmutableList.of(compensationColumnsEquiPred, otherCompensationPred))); // Generate query rewriting. RelNode rewrittenPlan = relBuilder .push(target) .filter(simplify.simplifyUnknownAsFalse(queryCompensationPred)) .build(); if (unionRewritingPullProgram != null) { rewrittenPlan = newNode.copy( newNode.getTraitSet(), ImmutableList.of(rewrittenPlan)); } if (topProject != null) { return topProject.copy(topProject.getTraitSet(), ImmutableList.of(rewrittenPlan)); } return rewrittenPlan; }
Example 18
Source File: CalciteRunners.java From Mycat2 with GNU General Public License v3.0 | 4 votes |
@SneakyThrows public static RowBaseIterator run(String sql, MycatCalciteDataContext calciteDataContext, RelNode relNode) { SqlRecorder recorder = SqlRecorderRuntime.INSTANCE.getCurrentRecorder(); Map<String, List<SingeTargetSQLTable>> map = new HashMap<>(); relNode.accept(new RelShuttleImpl() { @Override public RelNode visit(TableScan scan) { SingeTargetSQLTable unwrap = scan.getTable().unwrap(SingeTargetSQLTable.class); if (unwrap != null && !unwrap.existsEnumerable()) { List<SingeTargetSQLTable> tables = map.computeIfAbsent(unwrap.getTargetName(), s -> new ArrayList<>(2)); tables.add(unwrap); } return super.visit(scan); } }); HepProgramBuilder hepProgramBuilder = new HepProgramBuilder(); hepProgramBuilder.addMatchLimit(64); hepProgramBuilder.addRuleInstance(StreamUnionRule.INSTANCE); final HepPlanner planner2 = new HepPlanner(hepProgramBuilder.build()); planner2.setRoot(relNode); relNode = planner2.findBestExp(); //check relNode.accept(new RelShuttleImpl() { @Override public RelNode visit(LogicalUnion union) { if (union.getInputs().size() > 2) { throw new AssertionError("union input more 2"); } return super.visit(union); } }); long startGetConnectionTime = TimeProvider.INSTANCE.now(); fork(sql, calciteDataContext, map); long cbo = TimeProvider.INSTANCE.now(); recorder.addRecord(SqlRecorderType.GET_CONNECTION, sql, cbo - startGetConnectionTime); ArrayBindable bindable1 = Interpreters.bindable(relNode); long execution_start = TimeProvider.INSTANCE.now(); recorder.addRecord(SqlRecorderType.CBO, sql, execution_start - cbo); // EnumerableInterpretable.toBindable() Enumerable<Object[]> bind = bindable1.bind(calciteDataContext); Enumerator<Object[]> enumerator = bind.enumerator(); return new EnumeratorRowIterator(CalciteConvertors.getMycatRowMetaData(relNode.getRowType()), enumerator, () -> { recorder.addRecord(SqlRecorderType.EXECUTION_TIME, sql, TimeProvider.INSTANCE.now()-execution_start); recorder.addRecord(SqlRecorderType.AT_END, sql, TimeProvider.INSTANCE.now()); }); }
Example 19
Source File: AbstractMaterializedViewRule.java From Bats with Apache License 2.0 | 4 votes |
@Override protected RelNode rewriteQuery(RelBuilder relBuilder, RexBuilder rexBuilder, RexSimplify simplify, RelMetadataQuery mq, RexNode compensationColumnsEquiPred, RexNode otherCompensationPred, Project topProject, RelNode node, BiMap<RelTableRef, RelTableRef> viewToQueryTableMapping, EquivalenceClasses viewEC, EquivalenceClasses queryEC) { // Our target node is the node below the root, which should have the maximum // number of available expressions in the tree in order to maximize our // number of rewritings. // We create a project on top. If the program is available, we execute // it to maximize rewriting opportunities. For instance, a program might // pull up all the expressions that are below the aggregate so we can // introduce compensation filters easily. This is important depending on // the planner strategy. RelNode newNode = node; RelNode target = node; if (unionRewritingPullProgram != null) { final HepPlanner tmpPlanner = new HepPlanner(unionRewritingPullProgram); tmpPlanner.setRoot(newNode); newNode = tmpPlanner.findBestExp(); target = newNode.getInput(0); } // All columns required by compensating predicates must be contained // in the query. List<RexNode> queryExprs = extractReferences(rexBuilder, target); if (!compensationColumnsEquiPred.isAlwaysTrue()) { compensationColumnsEquiPred = rewriteExpression(rexBuilder, mq, target, target, queryExprs, viewToQueryTableMapping.inverse(), queryEC, false, compensationColumnsEquiPred); if (compensationColumnsEquiPred == null) { // Skip it return null; } } // For the rest, we use the query equivalence classes if (!otherCompensationPred.isAlwaysTrue()) { otherCompensationPred = rewriteExpression(rexBuilder, mq, target, target, queryExprs, viewToQueryTableMapping.inverse(), viewEC, true, otherCompensationPred); if (otherCompensationPred == null) { // Skip it return null; } } final RexNode queryCompensationPred = RexUtil.not(RexUtil.composeConjunction(rexBuilder, ImmutableList.of(compensationColumnsEquiPred, otherCompensationPred))); // Generate query rewriting. RelNode rewrittenPlan = relBuilder.push(target) .filter(simplify.simplifyUnknownAsFalse(queryCompensationPred)).build(); if (unionRewritingPullProgram != null) { rewrittenPlan = newNode.copy(newNode.getTraitSet(), ImmutableList.of(rewrittenPlan)); } if (topProject != null) { return topProject.copy(topProject.getTraitSet(), ImmutableList.of(rewrittenPlan)); } return rewrittenPlan; }
Example 20
Source File: MutableRelTest.java From calcite with Apache License 2.0 | 4 votes |
/** Verifies that after conversion to and from a MutableRel, the new * RelNode remains identical to the original RelNode. */ private static void checkConvertMutableRel( String rel, String sql, boolean decorrelate, List<RelOptRule> rules) { final SqlToRelTestBase test = new SqlToRelTestBase() { }; RelNode origRel = test.createTester().convertSqlToRel(sql).rel; if (decorrelate) { final RelBuilder relBuilder = RelFactories.LOGICAL_BUILDER.create(origRel.getCluster(), null); origRel = RelDecorrelator.decorrelateQuery(origRel, relBuilder); } if (rules != null) { final HepProgram hepProgram = new HepProgramBuilder().addRuleCollection(rules).build(); final HepPlanner hepPlanner = new HepPlanner(hepProgram); hepPlanner.setRoot(origRel); origRel = hepPlanner.findBestExp(); } // Convert to and from a mutable rel. final MutableRel mutableRel = MutableRels.toMutable(origRel); final RelNode newRel = MutableRels.fromMutable(mutableRel); // Check if the mutable rel digest contains the target rel. final String mutableRelStr = mutableRel.deep(); final String msg1 = "Mutable rel: " + mutableRelStr + " does not contain target rel: " + rel; assertTrue(mutableRelStr.contains(rel), msg1); // Check if the mutable rel's row-type is identical to the original // rel's row-type. final RelDataType origRelType = origRel.getRowType(); final RelDataType mutableRelType = mutableRel.rowType; final String msg2 = "Mutable rel's row type does not match with the original rel.\n" + "Original rel type: " + origRelType + ";\nMutable rel type: " + mutableRelType; assertTrue( equal( "origRelType", origRelType, "mutableRelType", mutableRelType, IGNORE), msg2); // Check if the new rel converted from the mutable rel is identical // to the original rel. final String origRelStr = RelOptUtil.toString(origRel); final String newRelStr = RelOptUtil.toString(newRel); final String msg3 = "The converted new rel is different from the original rel.\n" + "Original rel: " + origRelStr + ";\nNew rel: " + newRelStr; assertEquals(origRelStr, newRelStr, msg3); }