PageRenderTime 68ms CodeModel.GetById 15ms app.highlight 46ms RepoModel.GetById 1ms app.codeStats 0ms

/tags/release-0.0.0-rc0/hive/external/ql/src/java/org/apache/hadoop/hive/ql/parse/BaseSemanticAnalyzer.java

#
Java | 743 lines | 582 code | 69 blank | 92 comment | 107 complexity | b52b2ee9a7f6bdb2cbd3c0b358ddc6e9 MD5 | raw file
  1/**
  2 * Licensed to the Apache Software Foundation (ASF) under one
  3 * or more contributor license agreements.  See the NOTICE file
  4 * distributed with this work for additional information
  5 * regarding copyright ownership.  The ASF licenses this file
  6 * to you under the Apache License, Version 2.0 (the
  7 * "License"); you may not use this file except in compliance
  8 * with the License.  You may obtain a copy of the License at
  9 *
 10 *     http://www.apache.org/licenses/LICENSE-2.0
 11 *
 12 * Unless required by applicable law or agreed to in writing, software
 13 * distributed under the License is distributed on an "AS IS" BASIS,
 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 15 * See the License for the specific language governing permissions and
 16 * limitations under the License.
 17 */
 18
 19package org.apache.hadoop.hive.ql.parse;
 20
 21import java.io.Serializable;
 22import java.io.UnsupportedEncodingException;
 23import java.util.ArrayList;
 24import java.util.HashMap;
 25import java.util.HashSet;
 26import java.util.LinkedHashMap;
 27import java.util.LinkedHashSet;
 28import java.util.List;
 29import java.util.Map;
 30
 31import org.antlr.runtime.tree.CommonTree;
 32import org.antlr.runtime.tree.Tree;
 33import org.apache.commons.logging.Log;
 34import org.apache.commons.logging.LogFactory;
 35import org.apache.hadoop.hive.conf.HiveConf;
 36import org.apache.hadoop.hive.metastore.api.FieldSchema;
 37import org.apache.hadoop.hive.metastore.api.Order;
 38import org.apache.hadoop.hive.ql.Context;
 39import org.apache.hadoop.hive.ql.exec.FetchTask;
 40import org.apache.hadoop.hive.ql.exec.Task;
 41import org.apache.hadoop.hive.ql.exec.Utilities;
 42import org.apache.hadoop.hive.ql.hooks.LineageInfo;
 43import org.apache.hadoop.hive.ql.hooks.ReadEntity;
 44import org.apache.hadoop.hive.ql.hooks.WriteEntity;
 45import org.apache.hadoop.hive.ql.io.IgnoreKeyTextOutputFormat;
 46import org.apache.hadoop.hive.ql.io.RCFileInputFormat;
 47import org.apache.hadoop.hive.ql.io.RCFileOutputFormat;
 48import org.apache.hadoop.hive.ql.metadata.Hive;
 49import org.apache.hadoop.hive.ql.metadata.HiveException;
 50import org.apache.hadoop.hive.ql.metadata.InvalidTableException;
 51import org.apache.hadoop.hive.ql.metadata.Partition;
 52import org.apache.hadoop.hive.ql.metadata.Table;
 53import org.apache.hadoop.hive.ql.session.SessionState.LogHelper;
 54import org.apache.hadoop.hive.serde.Constants;
 55import org.apache.hadoop.hive.serde2.columnar.ColumnarSerDe;
 56import org.apache.hadoop.mapred.SequenceFileInputFormat;
 57import org.apache.hadoop.mapred.SequenceFileOutputFormat;
 58import org.apache.hadoop.mapred.TextInputFormat;
 59
 60/**
 61 * BaseSemanticAnalyzer.
 62 *
 63 */
 64public abstract class BaseSemanticAnalyzer {
 65  protected final Hive db;
 66  protected final HiveConf conf;
 67  protected List<Task<? extends Serializable>> rootTasks;
 68  protected FetchTask fetchTask;
 69  protected final Log LOG;
 70  protected final LogHelper console;
 71
 72  protected Context ctx;
 73  protected HashMap<String, String> idToTableNameMap;
 74
 75  public static int HIVE_COLUMN_ORDER_ASC = 1;
 76  public static int HIVE_COLUMN_ORDER_DESC = 0;
 77
 78  /**
 79   * ReadEntitites that are passed to the hooks.
 80   */
 81  protected HashSet<ReadEntity> inputs;
 82  /**
 83   * List of WriteEntities that are passed to the hooks.
 84   */
 85  protected HashSet<WriteEntity> outputs;
 86  /**
 87   * Lineage information for the query.
 88   */
 89  protected LineageInfo linfo;
 90
 91  protected static final String TEXTFILE_INPUT = TextInputFormat.class
 92      .getName();
 93  protected static final String TEXTFILE_OUTPUT = IgnoreKeyTextOutputFormat.class
 94      .getName();
 95  protected static final String SEQUENCEFILE_INPUT = SequenceFileInputFormat.class
 96      .getName();
 97  protected static final String SEQUENCEFILE_OUTPUT = SequenceFileOutputFormat.class
 98      .getName();
 99  protected static final String RCFILE_INPUT = RCFileInputFormat.class
100      .getName();
101  protected static final String RCFILE_OUTPUT = RCFileOutputFormat.class
102      .getName();
103  protected static final String COLUMNAR_SERDE = ColumnarSerDe.class.getName();
104
105  class RowFormatParams {
106    String fieldDelim = null;
107    String fieldEscape = null;
108    String collItemDelim = null;
109    String mapKeyDelim = null;
110    String lineDelim = null;
111
112    protected void analyzeRowFormat(AnalyzeCreateCommonVars shared, ASTNode child) throws SemanticException {
113      child = (ASTNode) child.getChild(0);
114      int numChildRowFormat = child.getChildCount();
115      for (int numC = 0; numC < numChildRowFormat; numC++) {
116        ASTNode rowChild = (ASTNode) child.getChild(numC);
117        switch (rowChild.getToken().getType()) {
118        case HiveParser.TOK_TABLEROWFORMATFIELD:
119          fieldDelim = unescapeSQLString(rowChild.getChild(0)
120              .getText());
121          if (rowChild.getChildCount() >= 2) {
122            fieldEscape = unescapeSQLString(rowChild
123                .getChild(1).getText());
124          }
125          break;
126        case HiveParser.TOK_TABLEROWFORMATCOLLITEMS:
127          collItemDelim = unescapeSQLString(rowChild
128              .getChild(0).getText());
129          break;
130        case HiveParser.TOK_TABLEROWFORMATMAPKEYS:
131          mapKeyDelim = unescapeSQLString(rowChild.getChild(0)
132              .getText());
133          break;
134        case HiveParser.TOK_TABLEROWFORMATLINES:
135          lineDelim = unescapeSQLString(rowChild.getChild(0)
136              .getText());
137          if (!lineDelim.equals("\n")
138              && !lineDelim.equals("10")) {
139            throw new SemanticException(
140                ErrorMsg.LINES_TERMINATED_BY_NON_NEWLINE.getMsg());
141          }
142          break;
143        default:
144          assert false;
145        }
146      }
147    }
148  }
149
150  class AnalyzeCreateCommonVars {
151    String serde = null;
152    Map<String, String> serdeProps = new HashMap<String, String>();
153  }
154
155  class StorageFormat {
156    String inputFormat = null;
157    String outputFormat = null;
158    String storageHandler = null;
159
160    protected boolean fillStorageFormat(ASTNode child, AnalyzeCreateCommonVars shared) {
161      boolean storageFormat = false;
162      switch(child.getToken().getType()) {
163      case HiveParser.TOK_TBLSEQUENCEFILE:
164        inputFormat = SEQUENCEFILE_INPUT;
165        outputFormat = SEQUENCEFILE_OUTPUT;
166        storageFormat = true;
167        break;
168      case HiveParser.TOK_TBLTEXTFILE:
169        inputFormat = TEXTFILE_INPUT;
170        outputFormat = TEXTFILE_OUTPUT;
171        storageFormat = true;
172        break;
173      case HiveParser.TOK_TBLRCFILE:
174        inputFormat = RCFILE_INPUT;
175        outputFormat = RCFILE_OUTPUT;
176        shared.serde = COLUMNAR_SERDE;
177        storageFormat = true;
178        break;
179      case HiveParser.TOK_TABLEFILEFORMAT:
180        inputFormat = unescapeSQLString(child.getChild(0).getText());
181        outputFormat = unescapeSQLString(child.getChild(1).getText());
182        storageFormat = true;
183        break;
184      case HiveParser.TOK_STORAGEHANDLER:
185        storageHandler = unescapeSQLString(child.getChild(0).getText());
186        if (child.getChildCount() == 2) {
187          readProps(
188            (ASTNode) (child.getChild(1).getChild(0)),
189            shared.serdeProps);
190        }
191        storageFormat = true;
192        break;
193      }
194      return storageFormat;
195    }
196
197    protected void fillDefaultStorageFormat(AnalyzeCreateCommonVars shared) {
198      if ((inputFormat == null) && (storageHandler == null)) {
199        if ("SequenceFile".equalsIgnoreCase(conf.getVar(HiveConf.ConfVars.HIVEDEFAULTFILEFORMAT))) {
200          inputFormat = SEQUENCEFILE_INPUT;
201          outputFormat = SEQUENCEFILE_OUTPUT;
202        } else if ("RCFile".equalsIgnoreCase(conf.getVar(HiveConf.ConfVars.HIVEDEFAULTFILEFORMAT))) {
203          inputFormat = RCFILE_INPUT;
204          outputFormat = RCFILE_OUTPUT;
205          shared.serde = COLUMNAR_SERDE;
206        } else {
207          inputFormat = TEXTFILE_INPUT;
208          outputFormat = TEXTFILE_OUTPUT;
209        }
210      }
211    }
212
213  }
214
215  public BaseSemanticAnalyzer(HiveConf conf) throws SemanticException {
216    try {
217      this.conf = conf;
218      db = Hive.get(conf);
219      rootTasks = new ArrayList<Task<? extends Serializable>>();
220      LOG = LogFactory.getLog(this.getClass().getName());
221      console = new LogHelper(LOG);
222      idToTableNameMap = new HashMap<String, String>();
223      inputs = new LinkedHashSet<ReadEntity>();
224      outputs = new LinkedHashSet<WriteEntity>();
225    } catch (Exception e) {
226      throw new SemanticException(e);
227    }
228  }
229
230  public HashMap<String, String> getIdToTableNameMap() {
231    return idToTableNameMap;
232  }
233
234  public abstract void analyzeInternal(ASTNode ast) throws SemanticException;
235
236  public void analyze(ASTNode ast, Context ctx) throws SemanticException {
237    this.ctx = ctx;
238    analyzeInternal(ast);
239  }
240
241  public void validate() throws SemanticException {
242    // Implementations may choose to override this
243  }
244
245  public List<Task<? extends Serializable>> getRootTasks() {
246    return rootTasks;
247  }
248
249  /**
250   * @return the fetchTask
251   */
252  public FetchTask getFetchTask() {
253    return fetchTask;
254  }
255
256  /**
257   * @param fetchTask
258   *          the fetchTask to set
259   */
260  public void setFetchTask(FetchTask fetchTask) {
261    this.fetchTask = fetchTask;
262  }
263
264  protected void reset() {
265    rootTasks = new ArrayList<Task<? extends Serializable>>();
266  }
267
268  public static String stripQuotes(String val) throws SemanticException {
269    if ((val.charAt(0) == '\'' && val.charAt(val.length() - 1) == '\'')
270        || (val.charAt(0) == '\"' && val.charAt(val.length() - 1) == '\"')) {
271      val = val.substring(1, val.length() - 1);
272    }
273    return val;
274  }
275
276  public static String charSetString(String charSetName, String charSetString)
277      throws SemanticException {
278    try {
279      // The character set name starts with a _, so strip that
280      charSetName = charSetName.substring(1);
281      if (charSetString.charAt(0) == '\'') {
282        return new String(unescapeSQLString(charSetString).getBytes(),
283            charSetName);
284      } else // hex input is also supported
285      {
286        assert charSetString.charAt(0) == '0';
287        assert charSetString.charAt(1) == 'x';
288        charSetString = charSetString.substring(2);
289
290        byte[] bArray = new byte[charSetString.length() / 2];
291        int j = 0;
292        for (int i = 0; i < charSetString.length(); i += 2) {
293          int val = Character.digit(charSetString.charAt(i), 16) * 16
294              + Character.digit(charSetString.charAt(i + 1), 16);
295          if (val > 127) {
296            val = val - 256;
297          }
298          bArray[j++] = new Integer(val).byteValue();
299        }
300
301        String res = new String(bArray, charSetName);
302        return res;
303      }
304    } catch (UnsupportedEncodingException e) {
305      throw new SemanticException(e);
306    }
307  }
308
309  /**
310   * @param Get the name from a table node
311   * @return if DB name is give, db.tab is returned. Otherwise, tab.
312   */
313  public static String getUnescapedName(ASTNode tableNameNode) {
314    if (tableNameNode.getToken().getType() == HiveParser.TOK_TABNAME) {
315      if (tableNameNode.getChildCount() == 2) {
316        String dbName = unescapeIdentifier(tableNameNode.getChild(0).getText());
317        String tableName = unescapeIdentifier(tableNameNode.getChild(1).getText());
318        return dbName + "." + tableName;
319      } else {
320        return unescapeIdentifier(tableNameNode.getChild(0).getText());
321      }
322    }
323    return unescapeIdentifier(tableNameNode.getText());
324  }
325
326  /**
327   * Remove the encapsulating "`" pair from the identifier. We allow users to
328   * use "`" to escape identifier for table names, column names and aliases, in
329   * case that coincide with Hive language keywords.
330   */
331  public static String unescapeIdentifier(String val) {
332    if (val == null) {
333      return null;
334    }
335    if (val.charAt(0) == '`' && val.charAt(val.length() - 1) == '`') {
336      val = val.substring(1, val.length() - 1);
337    }
338    return val;
339  }
340
341  /**
342   * Converts parsed key/value properties pairs into a map.
343   *
344   * @param prop ASTNode parent of the key/value pairs
345   *
346   * @param mapProp property map which receives the mappings
347   */
348  public static void readProps(
349    ASTNode prop, Map<String, String> mapProp) {
350
351    for (int propChild = 0; propChild < prop.getChildCount(); propChild++) {
352      String key = unescapeSQLString(prop.getChild(propChild).getChild(0)
353          .getText());
354      String value = unescapeSQLString(prop.getChild(propChild).getChild(1)
355          .getText());
356      mapProp.put(key, value);
357    }
358  }
359
360  @SuppressWarnings("nls")
361  public static String unescapeSQLString(String b) {
362
363    Character enclosure = null;
364
365    // Some of the strings can be passed in as unicode. For example, the
366    // delimiter can be passed in as \002 - So, we first check if the
367    // string is a unicode number, else go back to the old behavior
368    StringBuilder sb = new StringBuilder(b.length());
369    for (int i = 0; i < b.length(); i++) {
370
371      char currentChar = b.charAt(i);
372      if (enclosure == null) {
373        if (currentChar == '\'' || b.charAt(i) == '\"') {
374          enclosure = currentChar;
375        }
376        // ignore all other chars outside the enclosure
377        continue;
378      }
379
380      if (enclosure.equals(currentChar)) {
381        enclosure = null;
382        continue;
383      }
384
385      if (currentChar == '\\' && (i + 4 < b.length())) {
386        char i1 = b.charAt(i + 1);
387        char i2 = b.charAt(i + 2);
388        char i3 = b.charAt(i + 3);
389        if ((i1 >= '0' && i1 <= '1') && (i2 >= '0' && i2 <= '7')
390            && (i3 >= '0' && i3 <= '7')) {
391          byte bVal = (byte) ((i3 - '0') + ((i2 - '0') * 8) + ((i1 - '0') * 8 * 8));
392          byte[] bValArr = new byte[1];
393          bValArr[0] = bVal;
394          String tmp = new String(bValArr);
395          sb.append(tmp);
396          i += 3;
397          continue;
398        }
399      }
400
401      if (currentChar == '\\' && (i + 2 < b.length())) {
402        char n = b.charAt(i + 1);
403        switch (n) {
404        case '0':
405          sb.append("\0");
406          break;
407        case '\'':
408          sb.append("'");
409          break;
410        case '"':
411          sb.append("\"");
412          break;
413        case 'b':
414          sb.append("\b");
415          break;
416        case 'n':
417          sb.append("\n");
418          break;
419        case 'r':
420          sb.append("\r");
421          break;
422        case 't':
423          sb.append("\t");
424          break;
425        case 'Z':
426          sb.append("\u001A");
427          break;
428        case '\\':
429          sb.append("\\");
430          break;
431        // The following 2 lines are exactly what MySQL does
432        case '%':
433          sb.append("\\%");
434          break;
435        case '_':
436          sb.append("\\_");
437          break;
438        default:
439          sb.append(n);
440        }
441        i++;
442      } else {
443        sb.append(currentChar);
444      }
445    }
446    return sb.toString();
447  }
448
449  public HashSet<ReadEntity> getInputs() {
450    return inputs;
451  }
452
453  public HashSet<WriteEntity> getOutputs() {
454    return outputs;
455  }
456
457  /**
458   * @return the schema for the fields which will be produced
459   * when the statement is executed, or null if not known
460   */
461  public List<FieldSchema> getResultSchema() {
462    return null;
463  }
464
465  protected List<FieldSchema> getColumns(ASTNode ast) throws SemanticException {
466    return getColumns(ast, true);
467  }
468
469  protected void handleGenericFileFormat(ASTNode node) throws SemanticException{
470
471  ASTNode child = (ASTNode)node.getChild(0);
472  throw new SemanticException("Unrecognized file format in STORED AS clause:"+
473         " "+ (child == null ? "" : child.getText()));
474  }
475
476  /**
477   * Get the list of FieldSchema out of the ASTNode.
478   */
479  public static List<FieldSchema> getColumns(ASTNode ast, boolean lowerCase) throws SemanticException {
480    List<FieldSchema> colList = new ArrayList<FieldSchema>();
481    int numCh = ast.getChildCount();
482    for (int i = 0; i < numCh; i++) {
483      FieldSchema col = new FieldSchema();
484      ASTNode child = (ASTNode) ast.getChild(i);
485
486      String name = child.getChild(0).getText();
487      if(lowerCase) {
488        name = name.toLowerCase();
489      }
490      // child 0 is the name of the column
491      col.setName(unescapeIdentifier(name));
492      // child 1 is the type of the column
493      ASTNode typeChild = (ASTNode) (child.getChild(1));
494      col.setType(getTypeStringFromAST(typeChild));
495
496      // child 2 is the optional comment of the column
497      if (child.getChildCount() == 3) {
498        col.setComment(unescapeSQLString(child.getChild(2).getText()));
499      }
500      colList.add(col);
501    }
502    return colList;
503  }
504
505  protected List<String> getColumnNames(ASTNode ast) {
506    List<String> colList = new ArrayList<String>();
507    int numCh = ast.getChildCount();
508    for (int i = 0; i < numCh; i++) {
509      ASTNode child = (ASTNode) ast.getChild(i);
510      colList.add(unescapeIdentifier(child.getText()).toLowerCase());
511    }
512    return colList;
513  }
514
515  protected List<Order> getColumnNamesOrder(ASTNode ast) {
516    List<Order> colList = new ArrayList<Order>();
517    int numCh = ast.getChildCount();
518    for (int i = 0; i < numCh; i++) {
519      ASTNode child = (ASTNode) ast.getChild(i);
520      if (child.getToken().getType() == HiveParser.TOK_TABSORTCOLNAMEASC) {
521        colList.add(new Order(unescapeIdentifier(child.getChild(0).getText()).toLowerCase(),
522            HIVE_COLUMN_ORDER_ASC));
523      } else {
524        colList.add(new Order(unescapeIdentifier(child.getChild(0).getText()).toLowerCase(),
525            HIVE_COLUMN_ORDER_DESC));
526      }
527    }
528    return colList;
529  }
530
531  protected static String getTypeStringFromAST(ASTNode typeNode)
532      throws SemanticException {
533    switch (typeNode.getType()) {
534    case HiveParser.TOK_LIST:
535      return Constants.LIST_TYPE_NAME + "<"
536          + getTypeStringFromAST((ASTNode) typeNode.getChild(0)) + ">";
537    case HiveParser.TOK_MAP:
538      return Constants.MAP_TYPE_NAME + "<"
539          + getTypeStringFromAST((ASTNode) typeNode.getChild(0)) + ","
540          + getTypeStringFromAST((ASTNode) typeNode.getChild(1)) + ">";
541    case HiveParser.TOK_STRUCT:
542      return getStructTypeStringFromAST(typeNode);
543    case HiveParser.TOK_UNIONTYPE:
544      return getUnionTypeStringFromAST(typeNode);
545    default:
546      return DDLSemanticAnalyzer.getTypeName(typeNode.getType());
547    }
548  }
549
550  private static String getStructTypeStringFromAST(ASTNode typeNode)
551      throws SemanticException {
552    String typeStr = Constants.STRUCT_TYPE_NAME + "<";
553    typeNode = (ASTNode) typeNode.getChild(0);
554    int children = typeNode.getChildCount();
555    if (children <= 0) {
556      throw new SemanticException("empty struct not allowed.");
557    }
558    for (int i = 0; i < children; i++) {
559      ASTNode child = (ASTNode) typeNode.getChild(i);
560      typeStr += unescapeIdentifier(child.getChild(0).getText()) + ":";
561      typeStr += getTypeStringFromAST((ASTNode) child.getChild(1));
562      if (i < children - 1) {
563        typeStr += ",";
564      }
565    }
566
567    typeStr += ">";
568    return typeStr;
569  }
570
571  private static String getUnionTypeStringFromAST(ASTNode typeNode)
572      throws SemanticException {
573    String typeStr = Constants.UNION_TYPE_NAME + "<";
574    typeNode = (ASTNode) typeNode.getChild(0);
575    int children = typeNode.getChildCount();
576    if (children <= 0) {
577      throw new SemanticException("empty union not allowed.");
578    }
579    for (int i = 0; i < children; i++) {
580      typeStr += getTypeStringFromAST((ASTNode) typeNode.getChild(i));
581      if (i < children - 1) {
582        typeStr += ",";
583      }
584    }
585    typeStr += ">";
586    return typeStr;
587  }
588
589  /**
590   * tableSpec.
591   *
592   */
593  public static class tableSpec {
594    public String tableName;
595    public Table tableHandle;
596    public Map<String, String> partSpec; // has to use LinkedHashMap to enforce order
597    public Partition partHandle;
598    public int numDynParts; // number of dynamic partition columns
599    public List<Partition> partitions; // involved partitions in TableScanOperator/FileSinkOperator
600    public static enum SpecType {TABLE_ONLY, STATIC_PARTITION, DYNAMIC_PARTITION};
601    public SpecType specType;
602
603    public tableSpec(Hive db, HiveConf conf, ASTNode ast)
604        throws SemanticException {
605
606      assert (ast.getToken().getType() == HiveParser.TOK_TAB || ast.getToken().getType() == HiveParser.TOK_TABTYPE);
607      int childIndex = 0;
608      numDynParts = 0;
609
610      try {
611        // get table metadata
612        tableName = getUnescapedName((ASTNode)ast.getChild(0));
613        boolean testMode = conf.getBoolVar(HiveConf.ConfVars.HIVETESTMODE);
614        if (testMode) {
615          tableName = conf.getVar(HiveConf.ConfVars.HIVETESTMODEPREFIX)
616              + tableName;
617        }
618
619        tableHandle = db.getTable(tableName);
620      } catch (InvalidTableException ite) {
621        throw new SemanticException(ErrorMsg.INVALID_TABLE.getMsg(ast
622            .getChild(0)), ite);
623      } catch (HiveException e) {
624        throw new SemanticException(ErrorMsg.GENERIC_ERROR.getMsg(ast
625            .getChild(childIndex), e.getMessage()), e);
626      }
627
628      // get partition metadata if partition specified
629      if (ast.getChildCount() == 2) {
630        childIndex = 1;
631        ASTNode partspec = (ASTNode) ast.getChild(1);
632        partitions = new ArrayList<Partition>();
633        // partSpec is a mapping from partition column name to its value.
634        partSpec = new LinkedHashMap<String, String>(partspec.getChildCount());
635        for (int i = 0; i < partspec.getChildCount(); ++i) {
636          ASTNode partspec_val = (ASTNode) partspec.getChild(i);
637          String val = null;
638          String colName = unescapeIdentifier(partspec_val.getChild(0).getText().toLowerCase());
639          if (partspec_val.getChildCount() < 2) { // DP in the form of T partition (ds, hr)
640            ++numDynParts;
641          } else { // in the form of T partition (ds="2010-03-03")
642            val = stripQuotes(partspec_val.getChild(1).getText());
643          }
644          partSpec.put(colName, val);
645        }
646
647        // check if the columns specified in the partition() clause are actually partition columns
648        Utilities.validatePartSpec(tableHandle, partSpec);
649
650        // check if the partition spec is valid
651        if (numDynParts > 0) {
652          List<FieldSchema> parts = tableHandle.getPartitionKeys();
653          int numStaPart = parts.size() - numDynParts;
654          if (numStaPart == 0 &&
655              conf.getVar(HiveConf.ConfVars.DYNAMICPARTITIONINGMODE).equalsIgnoreCase("strict")) {
656            throw new SemanticException(ErrorMsg.DYNAMIC_PARTITION_STRICT_MODE.getMsg());
657          }
658        	for (FieldSchema fs: parts) {
659        	  if (partSpec.get(fs.getName().toLowerCase()) == null) {
660        	    if (numStaPart > 0) { // found a DP, but there exists ST as subpartition
661        	      throw new SemanticException(
662        	          ErrorMsg.PARTITION_DYN_STA_ORDER.getMsg(ast.getChild(childIndex)));
663        	    }
664        	    break;
665          	} else {
666          	  --numStaPart;
667          	}
668        	}
669          partHandle = null;
670          specType = SpecType.DYNAMIC_PARTITION;
671        } else {
672          try {
673            // this doesn't create partition.
674            partHandle = db.getPartition(tableHandle, partSpec, false);
675            if (partHandle == null) {
676              // if partSpec doesn't exists in DB, return a delegate one
677              // and the actual partition is created in MoveTask
678              partHandle = new Partition(tableHandle, partSpec, null);
679            } else {
680              partitions.add(partHandle);
681            }
682          } catch (HiveException e) {
683            throw new SemanticException(
684                ErrorMsg.INVALID_PARTITION.getMsg(ast.getChild(childIndex)));
685          }
686          specType = SpecType.STATIC_PARTITION;
687        }
688      } else {
689        specType = SpecType.TABLE_ONLY;
690      }
691    }
692
693    public Map<String, String> getPartSpec() {
694      return this.partSpec;
695    }
696
697    public void setPartSpec(Map<String, String> partSpec) {
698      this.partSpec = partSpec;
699    }
700
701    @Override
702    public String toString() {
703      if (partHandle != null) {
704        return partHandle.toString();
705      } else {
706        return tableHandle.toString();
707      }
708    }
709  }
710
711  /**
712   * Gets the lineage information.
713   *
714   * @return LineageInfo associated with the query.
715   */
716  public LineageInfo getLineageInfo() {
717    return linfo;
718  }
719
720  /**
721   * Sets the lineage information.
722   *
723   * @param linfo The LineageInfo structure that is set in the optimization phase.
724   */
725  public void setLineageInfo(LineageInfo linfo) {
726    this.linfo = linfo;
727  }
728
729  protected HashMap<String, String> extractPartitionSpecs(Tree partspec)
730      throws SemanticException {
731    HashMap<String, String> partSpec = new LinkedHashMap<String, String>();
732    for (int i = 0; i < partspec.getChildCount(); ++i) {
733      CommonTree partspec_val = (CommonTree) partspec.getChild(i);
734      String val = stripQuotes(partspec_val.getChild(1).getText());
735      partSpec.put(partspec_val.getChild(0).getText().toLowerCase(), val);
736    }
737    return partSpec;
738  }
739
740  public Hive getDb() {
741    return db;
742  }
743}