[ https://issues.apache.org/jira/browse/PHOENIX-1580?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=14393020#comment-14393020 ]
James Taylor commented on PHOENIX-1580: --------------------------------------- Thanks for the revisions, [~ayingshu]. Here's some more feedback: - Passing through the tableRef to UnionPlan as you're doing is fine. - In UnionCompiler, create static constant final PName member variables for the dummy table name and schema name so that you're not instantiating these again and again. I'd recommend calling them UNION_FAMILY_NAME, UNION_TABLE_NAME, and UNION_SCHEMA_NAME. We'll use the same names when UNION is implemented versus UNION ALL, so no need to have ALL in them. {code} + public static TableRef contructSchemaTable(PhoenixStatement statement, QueryPlan plan) throws SQLException { + List<PColumn> projectedColumns = new ArrayList<PColumn>(); + for (int i=0; i< plan.getProjector().getColumnCount(); i++) { + ColumnProjector colProj = plan.getProjector().getColumnProjector(i); + Expression sourceExpression = colProj.getExpression(); + PColumnImpl projectedColumn = new PColumnImpl(PNameFactory.newName(colProj.getName().getBytes()), PNameFactory.newName(DUMMY_FAMILY.getBytes()), + sourceExpression.getDataType(), sourceExpression.getMaxLength(), sourceExpression.getScale(), sourceExpression.isNullable(), + i, sourceExpression.getSortOrder(), 500, null, false, sourceExpression.toString()); + projectedColumns.add(projectedColumn); + } + Long scn = statement.getConnection().getSCN(); + PTable tempTable = PTableImpl.makePTable(statement.getConnection().getTenantId(), PNameFactory.newName(UNION_ALL_SCHEMA.getBytes()), PNameFactory.newName(UNION_ALL_TABLE.getBytes()), + PTableType.SUBQUERY, null, HConstants.LATEST_TIMESTAMP, scn == null ? HConstants.LATEST_TIMESTAMP : scn, null, null, projectedColumns, null, null, null, + true, null, null, null, true, true, true, null, null, null); + TableRef tableRef = new TableRef(null, tempTable, 0, false); + return tableRef; + } {code} - In the above code, construct your PName like this as it prevents a String from being created again: {code} new PColumnImpl(PNameFactory.newName(colProj.getName()) {code} - In UnionPlan, declare these member variables as constants. When you calculate isDegenerate just use a local variable in the constructor and initialize the member variables once with the final result: {code} + private boolean isDegenerate = true; + private final List<QueryPlan> plans; {code} - For the explain plan, you've essentially implemented part of the logic twice, in two different ways. Once in UnionPlan.getExplainPlan() where you loop over the query plans: {code} + @Override + public ExplainPlan getExplainPlan() throws SQLException { + List<String> steps = new ArrayList<String>(); + steps.add("UNION ALL " + iterators.size() + " queries\n"); + for (QueryPlan plan : this.getPlans()) { + List<String> planSteps = plan.getExplainPlan().getPlanSteps(); + steps.addAll(planSteps); + } {code} And then the same logic again in UnionResultIterators.explain(): {code} + @Override + public void explain(List<String> planSteps) { + for (int index=0; index < iterators.size(); index++) { + iterators.get(index).explain(planSteps); + } + } {code} Although both are correct, the former is much easier to understand. So I recommend you implement explain like this instead: {code} + @Override + public void explain(List<String> planSteps) { + for (QueryPlan plan : plans) { + List<String> planSteps = plan.getExplainPlan().getPlanSteps(); + steps.addAll(planSteps); + } + } {code} and modify the UnionPlan.getExplainPlan() to delegate to UnionResultIterators as you're already doing for many of the calls: {code} + @Override + public ExplainPlan getExplainPlan() throws SQLException { + List<String> steps = new ArrayList<String>(); + steps.add("UNION ALL " + iterators.size() + " queries\n"); + iterators.explain(steps); + if (!orderBy.getOrderByExpressions().isEmpty()) { + steps.add("CLIENT" + (limit == null ? "" : " TOP " + limit + " ROW" + (limit == 1 ? "" : "S")) + " SORTED BY " + orderBy.getOrderByExpressions().toString()); + } else if (limit != null) { + steps.add("CLIENT " + limit + " ROW LIMIT"); + } + + return new ExplainPlan(steps); + } {code} - In UnionResultIterators, size all the lists in the constructor, as you have a good idea of what the size will be: {code} +public class UnionResultIterators implements ResultIterators { + private final List<KeyRange> splits = new ArrayList<KeyRange>(); + private final List<List<Scan>> scans = new ArrayList<List<Scan>>(); + private final List<PeekingResultIterator> iterators = new ArrayList<PeekingResultIterator>(); + private final List<QueryPlan> plans; + + public UnionResultIterators(List<QueryPlan> plans) throws SQLException { + this.plans = plans; + for (QueryPlan plan : this.plans) { + iterators.add(LookAheadResultIterator.wrap(plan.iterator())); + if (plan.getSplits() != null) + splits.addAll(plan.getSplits()); + if (plan.getScans() != null) + scans.addAll(plan.getScans()); + } + } + {code} > Support UNION ALL > ----------------- > > Key: PHOENIX-1580 > URL: https://issues.apache.org/jira/browse/PHOENIX-1580 > Project: Phoenix > Issue Type: Bug > Reporter: Alicia Ying Shu > Assignee: Alicia Ying Shu > Attachments: PHOENIX-1580-grammar.patch, Phoenix-1580-v1.patch, > Phoenix-1580-v2.patch, Phoenix-1580-v3.patch, Phoenix-1580-v4.patch, > Phoenix-1580-v5.patch, Phoenix-1580-v6.patch, phoenix-1580-v1-wipe.patch, > phoenix-1580.patch, unionall-wipe.patch > > > Select * from T1 > UNION ALL > Select * from T2 -- This message was sent by Atlassian JIRA (v6.3.4#6332)