Impala
Impalaistheopensource,nativeanalyticdatabaseforApacheHadoop.
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
PlannerTestBase.java
Go to the documentation of this file.
1 // Copyright (c) 2012 Cloudera, Inc. All rights reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 package com.cloudera.impala.planner;
16 
17 import static org.junit.Assert.fail;
18 
19 import java.io.File;
20 import java.io.FileWriter;
21 import java.io.IOException;
22 import java.util.ArrayList;
23 import java.util.Arrays;
24 import java.util.Collections;
25 import java.util.List;
26 import java.util.Map;
27 import java.util.Set;
28 import java.util.regex.Matcher;
29 import java.util.regex.Pattern;
30 
31 import org.apache.hadoop.fs.Path;
32 import org.junit.AfterClass;
33 import org.junit.BeforeClass;
34 import org.slf4j.Logger;
35 import org.slf4j.LoggerFactory;
36 
51 import com.cloudera.impala.thrift.ImpalaInternalServiceConstants;
52 import com.cloudera.impala.thrift.TDescriptorTable;
53 import com.cloudera.impala.thrift.TExecRequest;
54 import com.cloudera.impala.thrift.TExplainLevel;
55 import com.cloudera.impala.thrift.THBaseKeyRange;
56 import com.cloudera.impala.thrift.THdfsFileSplit;
57 import com.cloudera.impala.thrift.THdfsPartition;
58 import com.cloudera.impala.thrift.THdfsScanNode;
59 import com.cloudera.impala.thrift.THdfsTable;
60 import com.cloudera.impala.thrift.TNetworkAddress;
61 import com.cloudera.impala.thrift.TPlanFragment;
62 import com.cloudera.impala.thrift.TPlanNode;
63 import com.cloudera.impala.thrift.TQueryCtx;
64 import com.cloudera.impala.thrift.TQueryExecRequest;
65 import com.cloudera.impala.thrift.TQueryOptions;
66 import com.cloudera.impala.thrift.TScanRangeLocations;
67 import com.cloudera.impala.thrift.TTableDescriptor;
68 import com.cloudera.impala.thrift.TTupleDescriptor;
69 import com.google.common.base.Joiner;
70 import com.google.common.base.Preconditions;
71 import com.google.common.collect.Lists;
72 import com.google.common.collect.Maps;
73 import com.google.common.collect.Sets;
74 
75 public class PlannerTestBase {
76  private final static Logger LOG = LoggerFactory.getLogger(PlannerTest.class);
77  private final static boolean GENERATE_OUTPUT_FILE = true;
78  private static Frontend frontend_ = new Frontend(
80  private final String testDir_ = "functional-planner/queries/PlannerTest";
81  private final String outDir_ = "/tmp/PlannerTest/";
82 
83  // Map from plan ID (TPlanNodeId) to the plan node with that ID.
84  private final Map<Integer, TPlanNode> planMap_ = Maps.newHashMap();
85  // Map from tuple ID (TTupleId) to the tuple descriptor with that ID.
86  private final Map<Integer, TTupleDescriptor> tupleMap_ = Maps.newHashMap();
87  // Map from table ID (TTableId) to the table descriptor with that ID.
88  private final Map<Integer, TTableDescriptor> tableMap_ = Maps.newHashMap();
89 
90  @BeforeClass
91  public static void setUp() throws Exception {
92  // Use 8 cores for resource estimation.
93  RuntimeEnv.INSTANCE.setNumCores(8);
94  // Set test env to control the explain level.
95  RuntimeEnv.INSTANCE.setTestEnv(true);
96  }
97 
98  @AfterClass
99  public static void cleanUp() {
100  RuntimeEnv.INSTANCE.reset();
101  }
102 
108  private void buildMaps(TQueryExecRequest execRequest) {
109  // Build maps that will be used by findPartition().
110  planMap_.clear();
111  tupleMap_.clear();
112  tableMap_.clear();
113  for (TPlanFragment frag: execRequest.fragments) {
114  for (TPlanNode node: frag.plan.nodes) {
115  planMap_.put(node.node_id, node);
116  }
117  }
118  if (execRequest.isSetDesc_tbl()) {
119  TDescriptorTable descTbl = execRequest.desc_tbl;
120  for (TTupleDescriptor tupleDesc: descTbl.tupleDescriptors) {
121  tupleMap_.put(tupleDesc.id, tupleDesc);
122  }
123  if (descTbl.isSetTableDescriptors()) {
124  for (TTableDescriptor tableDesc: descTbl.tableDescriptors) {
125  tableMap_.put(tableDesc.id, tableDesc);
126  }
127  }
128  }
129  }
130 
135  private THdfsPartition findPartition(int nodeId, THdfsFileSplit split) {
136  TPlanNode node = planMap_.get(nodeId);
137  Preconditions.checkNotNull(node);
138  Preconditions.checkState(node.node_id == nodeId && node.isSetHdfs_scan_node());
139  THdfsScanNode scanNode = node.getHdfs_scan_node();
140  int tupleId = scanNode.getTuple_id();
141  TTupleDescriptor tupleDesc = tupleMap_.get(tupleId);
142  Preconditions.checkNotNull(tupleDesc);
143  Preconditions.checkState(tupleDesc.id == tupleId);
144  TTableDescriptor tableDesc = tableMap_.get(tupleDesc.tableId);
145  Preconditions.checkNotNull(tableDesc);
146  Preconditions.checkState(tableDesc.id == tupleDesc.tableId &&
147  tableDesc.isSetHdfsTable());
148  THdfsTable hdfsTable = tableDesc.getHdfsTable();
149  THdfsPartition partition = hdfsTable.getPartitions().get(split.partition_id);
150  Preconditions.checkNotNull(partition);
151  Preconditions.checkState(partition.id == split.partition_id);
152  return partition;
153  }
154 
161  private void testHdfsPartitionsReferenced(TQueryExecRequest execRequest,
162  String query, StringBuilder errorLog) {
163  long insertTableId = -1;
164  // Collect all partitions that are referenced by a scan range.
165  Set<THdfsPartition> scanRangePartitions = Sets.newHashSet();
166  if (execRequest.per_node_scan_ranges != null) {
167  for (Map.Entry<Integer, List<TScanRangeLocations>> entry:
168  execRequest.per_node_scan_ranges.entrySet()) {
169  if (entry.getValue() == null) {
170  continue;
171  }
172  for (TScanRangeLocations locations: entry.getValue()) {
173  if (locations.scan_range.isSetHdfs_file_split()) {
174  THdfsFileSplit split = locations.scan_range.getHdfs_file_split();
175  THdfsPartition partition = findPartition(entry.getKey(), split);
176  scanRangePartitions.add(partition);
177  }
178  }
179  }
180  }
181  if (execRequest.isSetFinalize_params()) {
182  insertTableId = execRequest.getFinalize_params().getTable_id();
183  }
184  boolean first = true;
185  // Iterate through all partitions of the descriptor table and verify all partitions
186  // are referenced.
187  if (execRequest.isSetDesc_tbl() && execRequest.desc_tbl.isSetTableDescriptors()) {
188  for (TTableDescriptor tableDesc: execRequest.desc_tbl.tableDescriptors) {
189  // All partitions of insertTableId are okay.
190  if (tableDesc.getId() == insertTableId) continue;
191  if (!tableDesc.isSetHdfsTable()) continue;
192  THdfsTable hdfsTable = tableDesc.getHdfsTable();
193  for (Map.Entry<Long, THdfsPartition> e :
194  hdfsTable.getPartitions().entrySet()) {
195  THdfsPartition partition = e.getValue();
196  if (!scanRangePartitions.contains(partition)) {
197  if (first) errorLog.append("query:\n" + query + "\n");
198  errorLog.append(
199  " unreferenced partition: HdfsTable: " + tableDesc.getId() +
200  " HdfsPartition: " + partition.getId() + "\n");
201  first = false;
202  }
203  }
204  }
205  }
206  }
207 
211  private StringBuilder PrintScanRangeLocations(TQueryExecRequest execRequest) {
212  StringBuilder result = new StringBuilder();
213  if (execRequest.per_node_scan_ranges == null) {
214  return result;
215  }
216  for (Map.Entry<Integer, List<TScanRangeLocations>> entry:
217  execRequest.per_node_scan_ranges.entrySet()) {
218  result.append("NODE " + entry.getKey().toString() + ":\n");
219  if (entry.getValue() == null) {
220  continue;
221  }
222 
223  for (TScanRangeLocations locations: entry.getValue()) {
224  // print scan range
225  result.append(" ");
226  if (locations.scan_range.isSetHdfs_file_split()) {
227  THdfsFileSplit split = locations.scan_range.getHdfs_file_split();
228  THdfsPartition partition = findPartition(entry.getKey(), split);
229  Path filePath = new Path(partition.getLocation(), split.file_name);
230  filePath = cleanseFilePath(filePath);
231  result.append("HDFS SPLIT " + filePath.toString() + " "
232  + Long.toString(split.offset) + ":" + Long.toString(split.length));
233  }
234  if (locations.scan_range.isSetHbase_key_range()) {
235  THBaseKeyRange keyRange = locations.scan_range.getHbase_key_range();
236  Integer hostIdx = locations.locations.get(0).host_idx;
237  TNetworkAddress networkAddress = execRequest.getHost_list().get(hostIdx);
238  result.append("HBASE KEYRANGE ");
239  result.append("port=" + networkAddress.port + " ");
240  if (keyRange.isSetStartKey()) {
241  result.append(HBaseScanNode.printKey(keyRange.getStartKey().getBytes()));
242  } else {
243  result.append("<unbounded>");
244  }
245  result.append(":");
246  if (keyRange.isSetStopKey()) {
247  result.append(HBaseScanNode.printKey(keyRange.getStopKey().getBytes()));
248  } else {
249  result.append("<unbounded>");
250  }
251  }
252  result.append("\n");
253  }
254  }
255  return result;
256  }
257 
264  protected Path cleanseFilePath(Path path) {
265  String fileName = path.getName();
266  Pattern pattern = Pattern.compile("\\w{16}-\\w{16}_\\d+_data");
267  Matcher matcher = pattern.matcher(fileName);
268  fileName = matcher.replaceFirst("<UID>_data");
269  return new Path(path.getParent(), fileName);
270  }
271 
279  private String getExpectedErrorMessage(ArrayList<String> expectedPlan) {
280  if (expectedPlan.isEmpty()) return null;
281  if (!expectedPlan.get(0).toLowerCase().startsWith("not implemented")) return null;
282  // Find first ':' and extract string on right hand side as error message.
283  int ix = expectedPlan.get(0).indexOf(":");
284  if (ix + 1 > 0) {
285  return expectedPlan.get(0).substring(ix + 1).trim();
286  } else {
287  return "";
288  }
289  }
290 
291  private void handleNotImplException(String query, String expectedErrorMsg,
292  StringBuilder errorLog, StringBuilder actualOutput, Throwable e) {
293  boolean isImplemented = expectedErrorMsg == null;
294  actualOutput.append("not implemented: " + e.getMessage() + "\n");
295  if (isImplemented) {
296  errorLog.append("query:\n" + query + "\nPLAN not implemented: "
297  + e.getMessage() + "\n");
298  } else {
299  // Compare actual and expected error messages.
300  if (expectedErrorMsg != null && !expectedErrorMsg.isEmpty()) {
301  if (!e.getMessage().toLowerCase().equals(expectedErrorMsg.toLowerCase())) {
302  errorLog.append("query:\n" + query + "\nExpected error message: '"
303  + expectedErrorMsg + "'\nActual error message: '"
304  + e.getMessage() + "'\n");
305  }
306  }
307  }
308  }
309 
313  private TQueryOptions mergeQueryOptions(TQueryOptions a, TQueryOptions b) {
314  for(TQueryOptions._Fields f : TQueryOptions._Fields.values()) {
315  if (b.isSet(f)) {
316  a.setFieldValue(f, b.getFieldValue(f));
317  }
318  }
319  return a;
320  }
321 
322  private TQueryOptions defaultQueryOptions() {
323  TQueryOptions options = new TQueryOptions();
324  options.setExplain_level(TExplainLevel.STANDARD);
325  options.setAllow_unsupported_formats(true);
326  options.setExec_single_node_rows_threshold(0);
327  return options;
328  }
329 
338  private void RunTestCase(TestCase testCase, StringBuilder errorLog,
339  StringBuilder actualOutput, String dbName, TQueryOptions options)
340  throws CatalogException {
341 
342  if (options == null) {
343  options = defaultQueryOptions();
344  } else {
345  options = mergeQueryOptions(defaultQueryOptions(), options);
346  }
347 
348  String query = testCase.getQuery();
349  LOG.info("running query " + query);
350  if (query.isEmpty()) {
351  throw new IllegalStateException("Cannot plan empty query in line: " +
352  testCase.getStartingLineNum());
353  }
354  TQueryCtx queryCtx = TestUtils.createQueryContext(
355  dbName, System.getProperty("user.name"));
356  queryCtx.request.query_options = options;
357  // single-node plan and scan range locations
358  testSingleNodePlan(testCase, queryCtx, errorLog, actualOutput);
359  testDistributedPlan(testCase, queryCtx, errorLog, actualOutput);
360  testColumnLineageOutput(testCase, queryCtx, errorLog, actualOutput);
361  }
362 
368  private void testSingleNodePlan(TestCase testCase, TQueryCtx queryCtx,
369  StringBuilder errorLog, StringBuilder actualOutput) throws CatalogException {
370  ArrayList<String> expectedPlan = testCase.getSectionContents(Section.PLAN);
371  // Test case has no expected single-node plan. Do not test it.
372  if (expectedPlan == null || expectedPlan.isEmpty()) return;
373  String query = testCase.getQuery();
374  String expectedErrorMsg = getExpectedErrorMessage(expectedPlan);
375  queryCtx.request.getQuery_options().setNum_nodes(1);
376  queryCtx.request.setStmt(query);
377  boolean isImplemented = expectedErrorMsg == null;
378  StringBuilder explainBuilder = new StringBuilder();
379 
380  TExecRequest execRequest = null;
381  String locationsStr = null;
382  actualOutput.append(Section.PLAN.getHeader() + "\n");
383  try {
384  execRequest = frontend_.createExecRequest(queryCtx, explainBuilder);
385  buildMaps(execRequest.query_exec_request);
386  String explainStr = removeExplainHeader(explainBuilder.toString());
387  actualOutput.append(explainStr);
388  if (!isImplemented) {
389  errorLog.append(
390  "query produced PLAN\nquery=" + query + "\nplan=\n" + explainStr);
391  } else {
392  LOG.info("single-node plan: " + explainStr);
393  String result = TestUtils.compareOutput(
394  Lists.newArrayList(explainStr.split("\n")), expectedPlan, true);
395  if (!result.isEmpty()) {
396  errorLog.append("section " + Section.PLAN.toString() + " of query:\n" + query
397  + "\n" + result);
398  }
399  // Query exec request may not be set for DDL, e.g., CTAS.
400  if (execRequest.isSetQuery_exec_request()) {
401  testHdfsPartitionsReferenced(execRequest.query_exec_request, query, errorLog);
402  locationsStr =
403  PrintScanRangeLocations(execRequest.query_exec_request).toString();
404  }
405  }
406  } catch (ImpalaException e) {
407  if (e instanceof AnalysisException) {
408  errorLog.append(
409  "query:\n" + query + "\nanalysis error: " + e.getMessage() + "\n");
410  return;
411  } else if (e instanceof InternalException) {
412  errorLog.append(
413  "query:\n" + query + "\ninternal error: " + e.getMessage() + "\n");
414  return;
415  } if (e instanceof NotImplementedException) {
416  handleNotImplException(query, expectedErrorMsg, errorLog, actualOutput, e);
417  } else if (e instanceof CatalogException) {
418  // TODO: do we need to rethrow?
419  throw (CatalogException) e;
420  } else {
421  errorLog.append(
422  "query:\n" + query + "\nunhandled exception: " + e.getMessage() + "\n");
423  }
424  }
425 
426  // compare scan range locations
427  LOG.info("scan range locations: " + locationsStr);
428  ArrayList<String> expectedLocations =
429  testCase.getSectionContents(Section.SCANRANGELOCATIONS);
430 
431  if (expectedLocations.size() > 0 && locationsStr != null) {
432  // Locations' order does not matter.
433  String result = TestUtils.compareOutput(
434  Lists.newArrayList(locationsStr.split("\n")), expectedLocations, false);
435  if (!result.isEmpty()) {
436  errorLog.append("section " + Section.SCANRANGELOCATIONS + " of query:\n"
437  + query + "\n" + result);
438  }
439  actualOutput.append(Section.SCANRANGELOCATIONS.getHeader() + "\n");
440  // Print the locations out sorted since the order is random and messed up
441  // the diffs. The values in locationStr contains "Node X" labels as well
442  // as paths.
443  ArrayList<String> locations = Lists.newArrayList(locationsStr.split("\n"));
444  ArrayList<String> perNodeLocations = Lists.newArrayList();
445 
446  for (int i = 0; i < locations.size(); ++i) {
447  if (locations.get(i).startsWith("NODE")) {
448  if (!perNodeLocations.isEmpty()) {
449  Collections.sort(perNodeLocations);
450  actualOutput.append(Joiner.on("\n").join(perNodeLocations)).append("\n");
451  perNodeLocations.clear();
452  }
453  actualOutput.append(locations.get(i)).append("\n");
454  } else {
455  perNodeLocations.add(locations.get(i));
456  }
457  }
458 
459  if (!perNodeLocations.isEmpty()) {
460  Collections.sort(perNodeLocations);
461  actualOutput.append(Joiner.on("\n").join(perNodeLocations)).append("\n");
462  }
463 
464  // TODO: check that scan range locations are identical in both cases
465  }
466  }
467 
468  private void testColumnLineageOutput(TestCase testCase, TQueryCtx queryCtx,
469  StringBuilder errorLog, StringBuilder actualOutput) throws CatalogException {
470  ArrayList<String> expectedLineage = testCase.getSectionContents(Section.LINEAGE);
471  if (expectedLineage == null || expectedLineage.isEmpty()) return;
472  String query = testCase.getQuery();
473  queryCtx.request.getQuery_options().setNum_nodes(1);
474  queryCtx.request.setStmt(query);
475  StringBuilder explainBuilder = new StringBuilder();
476  TExecRequest execRequest = null;
477  String lineageGraph = null;
478  try {
479  execRequest = frontend_.createExecRequest(queryCtx, explainBuilder);
480  if (execRequest.isSetQuery_exec_request()) {
481  lineageGraph = execRequest.query_exec_request.lineage_graph;
482  } else if (execRequest.isSetCatalog_op_request()) {
483  lineageGraph = execRequest.catalog_op_request.lineage_graph;
484  }
485  } catch (ImpalaException e) {
486  if (e instanceof AnalysisException) {
487  errorLog.append(
488  "query:\n" + query + "\nanalysis error: " + e.getMessage() + "\n");
489  return;
490  } else if (e instanceof InternalException) {
491  errorLog.append(
492  "query:\n" + query + "\ninternal error: " + e.getMessage() + "\n");
493  return;
494  } if (e instanceof NotImplementedException) {
495  handleNotImplException(query, "", errorLog, actualOutput, e);
496  } else if (e instanceof CatalogException) {
497  throw (CatalogException) e;
498  } else {
499  errorLog.append(
500  "query:\n" + query + "\nunhandled exception: " + e.getMessage() + "\n");
501  }
502  }
503  LOG.info("lineage graph: " + lineageGraph);
504  ArrayList<String> expected =
505  testCase.getSectionContents(Section.LINEAGE);
506  if (expected.size() > 0 && lineageGraph != null) {
507  String serializedGraph = Joiner.on("\n").join(expected);
508  ColumnLineageGraph expectedGraph =
509  ColumnLineageGraph.createFromJSON(serializedGraph);
510  ColumnLineageGraph outputGraph =
511  ColumnLineageGraph.createFromJSON(lineageGraph);
512  if (expectedGraph == null || outputGraph == null ||
513  !outputGraph.equals(expectedGraph)) {
514  StringBuilder lineageError = new StringBuilder();
515  lineageError.append("section " + Section.LINEAGE + " of query:\n"
516  + query + "\n");
517  lineageError.append("Output:\n");
518  lineageError.append(lineageGraph + "\n");
519  lineageError.append("Expected:\n");
520  lineageError.append(serializedGraph + "\n");
521  errorLog.append(lineageError.toString());
522  }
523  actualOutput.append(Section.LINEAGE.getHeader());
524  actualOutput.append(TestUtils.prettyPrintJson(lineageGraph) + "\n");
525  }
526  }
527 
532  private void testDistributedPlan(TestCase testCase, TQueryCtx queryCtx,
533  StringBuilder errorLog, StringBuilder actualOutput) throws CatalogException {
534  ArrayList<String> expectedPlan =
535  testCase.getSectionContents(Section.DISTRIBUTEDPLAN);
536  // Test case has no expected distributed plan. Do not test it.
537  if (expectedPlan == null || expectedPlan.isEmpty()) return;
538 
539  String query = testCase.getQuery();
540  String expectedErrorMsg = getExpectedErrorMessage(expectedPlan);
541  queryCtx.request.getQuery_options().setNum_nodes(
542  ImpalaInternalServiceConstants.NUM_NODES_ALL);
543  queryCtx.request.setStmt(query);
544  boolean isImplemented = expectedErrorMsg == null;
545  StringBuilder explainBuilder = new StringBuilder();
546  actualOutput.append(Section.DISTRIBUTEDPLAN.getHeader() + "\n");
547  TExecRequest execRequest = null;
548  try {
549  // distributed plan
550  execRequest = frontend_.createExecRequest(queryCtx, explainBuilder);
551  String explainStr = removeExplainHeader(explainBuilder.toString());
552  actualOutput.append(explainStr);
553  if (!isImplemented) {
554  errorLog.append(
555  "query produced DISTRIBUTEDPLAN\nquery=" + query + "\nplan=\n"
556  + explainStr);
557  } else {
558  LOG.info("distributed plan: " + explainStr);
559  String result = TestUtils.compareOutput(
560  Lists.newArrayList(explainStr.split("\n")), expectedPlan, true);
561  if (!result.isEmpty()) {
562  errorLog.append("section " + Section.DISTRIBUTEDPLAN.toString()
563  + " of query:\n" + query + "\n" + result);
564  }
565  }
566  } catch (ImpalaException e) {
567  if (e instanceof AnalysisException) {
568  errorLog.append(
569  "query:\n" + query + "\nanalysis error: " + e.getMessage() + "\n");
570  return;
571  } else if (e instanceof InternalException) {
572  errorLog.append(
573  "query:\n" + query + "\ninternal error: " + e.getMessage() + "\n");
574  return;
575  } if (e instanceof NotImplementedException) {
576  handleNotImplException(query, expectedErrorMsg, errorLog, actualOutput, e);
577  } else if (e instanceof CatalogException) {
578  throw (CatalogException) e;
579  } else {
580  errorLog.append(
581  "query:\n" + query + "\nunhandled exception: " + e.getMessage() + "\n");
582  }
583  } catch (IllegalStateException e) {
584  errorLog.append(
585  "query:\n" + query + "\nunhandled exception: " + e.getMessage() + "\n");
586  }
587  }
588 
594  private String removeExplainHeader(String explain) {
595  String[] lines = explain.split("\n");
596  // Find the first empty line - the end of the header.
597  for (int i = 0; i < lines.length - 1; ++i) {
598  if (lines[i].isEmpty()) {
599  return Joiner.on("\n").join(Arrays.copyOfRange(lines, i + 1 , lines.length))
600  + "\n";
601  }
602  }
603  return explain;
604  }
605 
606  protected void runPlannerTestFile(String testFile, TQueryOptions options) {
607  runPlannerTestFile(testFile, "default", options);
608  }
609 
610  private void runPlannerTestFile(String testFile, String dbName, TQueryOptions options) {
611  String fileName = testDir_ + "/" + testFile + ".test";
612  TestFileParser queryFileParser = new TestFileParser(fileName);
613  StringBuilder actualOutput = new StringBuilder();
614 
615  queryFileParser.parseFile();
616  StringBuilder errorLog = new StringBuilder();
617  for (TestCase testCase : queryFileParser.getTestCases()) {
618  actualOutput.append(testCase.getSectionAsString(Section.QUERY, true, "\n"));
619  actualOutput.append("\n");
620  try {
621  RunTestCase(testCase, errorLog, actualOutput, dbName, options);
622  } catch (CatalogException e) {
623  errorLog.append(String.format("Failed to plan query\n%s\n%s",
624  testCase.getQuery(), e.getMessage()));
625  }
626  actualOutput.append("====\n");
627  }
628 
629  // Create the actual output file
630  if (GENERATE_OUTPUT_FILE) {
631  try {
632  File outDirFile = new File(outDir_);
633  outDirFile.mkdirs();
634  FileWriter fw = new FileWriter(outDir_ + testFile + ".test");
635  fw.write(actualOutput.toString());
636  fw.close();
637  } catch (IOException e) {
638  errorLog.append("Unable to create output file: " + e.getMessage());
639  }
640  }
641 
642  if (errorLog.length() != 0) {
643  fail(errorLog.toString());
644  }
645  }
646 
647  protected void runPlannerTestFile(String testFile) {
648  runPlannerTestFile(testFile, "default", null);
649  }
650 
651  protected void runPlannerTestFile(String testFile, String dbName) {
652  runPlannerTestFile(testFile, dbName, null);
653  }
654 }
655 
void handleNotImplException(String query, String expectedErrorMsg, StringBuilder errorLog, StringBuilder actualOutput, Throwable e)
string path("/usr/lib/sasl2:/usr/lib64/sasl2:/usr/local/lib/sasl2:/usr/lib/x86_64-linux-gnu/sasl2")
void testSingleNodePlan(TestCase testCase, TQueryCtx queryCtx, StringBuilder errorLog, StringBuilder actualOutput)
void buildMaps(TQueryExecRequest execRequest)
final Map< Integer, TTableDescriptor > tableMap_
THdfsPartition findPartition(int nodeId, THdfsFileSplit split)
void testDistributedPlan(TestCase testCase, TQueryCtx queryCtx, StringBuilder errorLog, StringBuilder actualOutput)
void RunTestCase(TestCase testCase, StringBuilder errorLog, StringBuilder actualOutput, String dbName, TQueryOptions options)
TQueryOptions mergeQueryOptions(TQueryOptions a, TQueryOptions b)
final Map< Integer, TTupleDescriptor > tupleMap_
String getExpectedErrorMessage(ArrayList< String > expectedPlan)
void runPlannerTestFile(String testFile, String dbName)
void testColumnLineageOutput(TestCase testCase, TQueryCtx queryCtx, StringBuilder errorLog, StringBuilder actualOutput)
void runPlannerTestFile(String testFile, TQueryOptions options)
void runPlannerTestFile(String testFile, String dbName, TQueryOptions options)
void testHdfsPartitionsReferenced(TQueryExecRequest execRequest, String query, StringBuilder errorLog)
final Map< Integer, TPlanNode > planMap_
StringBuilder PrintScanRangeLocations(TQueryExecRequest execRequest)