public LiteralParseNode literal(String value, String sqlTypeName) throws SQLException {
   PDataType expectedType =
       sqlTypeName == null
           ? null
           : PDataType.fromSqlTypeName(SchemaUtil.normalizeIdentifier(sqlTypeName));
   if (expectedType == null || !expectedType.isCoercibleTo(PTimestamp.INSTANCE)) {
     throw TypeMismatchException.newException(expectedType, PTimestamp.INSTANCE);
   }
   Object typedValue = expectedType.toObject(value);
   return new LiteralParseNode(typedValue);
 }
Example #2
0
  /**
   * Get list of ColumnInfos that contain Column Name and its associated PDataType for an import.
   * The supplied list of columns can be null -- if it is non-null, it represents a user-supplied
   * list of columns to be imported.
   *
   * @param conn Phoenix connection from which metadata will be read
   * @param tableName Phoenix table name whose columns are to be checked. Can include a schema name
   * @param columns user-supplied list of import columns, can be null
   * @param strict if true, an exception will be thrown if unknown columns are supplied
   */
  public static List<ColumnInfo> generateColumnInfo(
      Connection conn, String tableName, List<String> columns, boolean strict) throws SQLException {
    Map<String, Integer> columnNameToTypeMap = Maps.newLinkedHashMap();
    Set<String> ambiguousColumnNames = new HashSet<String>();
    Map<String, Integer> fullColumnNameToTypeMap = Maps.newLinkedHashMap();
    DatabaseMetaData dbmd = conn.getMetaData();
    int unfoundColumnCount = 0;
    // TODO: escape wildcard characters here because we don't want that
    // behavior here
    String escapedTableName = StringUtil.escapeLike(tableName);
    String[] schemaAndTable = escapedTableName.split("\\.");
    ResultSet rs = null;
    try {
      rs =
          dbmd.getColumns(
              null,
              (schemaAndTable.length == 1 ? "" : schemaAndTable[0]),
              (schemaAndTable.length == 1 ? escapedTableName : schemaAndTable[1]),
              null);
      while (rs.next()) {
        String colName = rs.getString(QueryUtil.COLUMN_NAME_POSITION);
        String colFam = rs.getString(QueryUtil.COLUMN_FAMILY_POSITION);

        // use family qualifier, if available, otherwise, use column name
        String fullColumn = (colFam == null ? colName : String.format("%s.%s", colFam, colName));
        String sqlTypeName = rs.getString(QueryUtil.DATA_TYPE_NAME_POSITION);

        // allow for both bare and family qualified names.
        if (columnNameToTypeMap.keySet().contains(colName)) {
          ambiguousColumnNames.add(colName);
        }
        columnNameToTypeMap.put(colName, PDataType.fromSqlTypeName(sqlTypeName).getSqlType());
        fullColumnNameToTypeMap.put(
            fullColumn, PDataType.fromSqlTypeName(sqlTypeName).getSqlType());
      }
      if (columnNameToTypeMap.isEmpty()) {
        throw new IllegalArgumentException("Table " + tableName + " not found");
      }
    } finally {
      if (rs != null) {
        rs.close();
      }
    }
    List<ColumnInfo> columnInfoList = Lists.newArrayList();
    Set<String> unresolvedColumnNames = new TreeSet<String>();
    if (columns == null) {
      // use family qualified names by default, if no columns are specified.
      for (Map.Entry<String, Integer> entry : fullColumnNameToTypeMap.entrySet()) {
        columnInfoList.add(new ColumnInfo(entry.getKey(), entry.getValue()));
      }
    } else {
      // Leave "null" as indication to skip b/c it doesn't exist
      for (int i = 0; i < columns.size(); i++) {
        String columnName = columns.get(i).trim();
        Integer sqlType = null;
        if (fullColumnNameToTypeMap.containsKey(columnName)) {
          sqlType = fullColumnNameToTypeMap.get(columnName);
        } else if (columnNameToTypeMap.containsKey(columnName)) {
          if (ambiguousColumnNames.contains(columnName)) {
            unresolvedColumnNames.add(columnName);
          }
          // fall back to bare column name.
          sqlType = columnNameToTypeMap.get(columnName);
        }
        if (unresolvedColumnNames.size() > 0) {
          StringBuilder exceptionMessage = new StringBuilder();
          boolean first = true;
          exceptionMessage.append(
              "Unable to resolve these column names to a single column family:\n");
          for (String col : unresolvedColumnNames) {
            if (first) first = false;
            else exceptionMessage.append(",");
            exceptionMessage.append(col);
          }
          exceptionMessage.append("\nAvailable columns with column families:\n");
          first = true;
          for (String col : fullColumnNameToTypeMap.keySet()) {
            if (first) first = false;
            else exceptionMessage.append(",");
            exceptionMessage.append(col);
          }
          throw new SQLException(exceptionMessage.toString());
        }

        if (sqlType == null) {
          if (strict) {
            throw new SQLExceptionInfo.Builder(SQLExceptionCode.COLUMN_NOT_FOUND)
                .setColumnName(columnName)
                .setTableName(tableName)
                .build()
                .buildException();
          }
          unfoundColumnCount++;
        } else {
          columnInfoList.add(new ColumnInfo(columnName, sqlType));
        }
      }
      if (unfoundColumnCount == columns.size()) {
        throw new SQLExceptionInfo.Builder(SQLExceptionCode.COLUMN_NOT_FOUND)
            .setColumnName(Arrays.toString(columns.toArray(new String[0])))
            .setTableName(tableName)
            .build()
            .buildException();
      }
    }
    return columnInfoList;
  }