|
255 | 255 | import static com.facebook.presto.hive.HiveTableProperties.ORC_BLOOM_FILTER_FPP; |
256 | 256 | import static com.facebook.presto.hive.HiveTableProperties.PARTITIONED_BY_PROPERTY; |
257 | 257 | import static com.facebook.presto.hive.HiveTableProperties.PREFERRED_ORDERING_COLUMNS; |
| 258 | +import static com.facebook.presto.hive.HiveTableProperties.SKIP_FOOTER_LINE_COUNT; |
| 259 | +import static com.facebook.presto.hive.HiveTableProperties.SKIP_HEADER_LINE_COUNT; |
258 | 260 | import static com.facebook.presto.hive.HiveTableProperties.SORTED_BY_PROPERTY; |
259 | 261 | import static com.facebook.presto.hive.HiveTableProperties.STORAGE_FORMAT_PROPERTY; |
260 | 262 | import static com.facebook.presto.hive.HiveTableProperties.getAvroSchemaUrl; |
|
265 | 267 | import static com.facebook.presto.hive.HiveTableProperties.getEncryptColumns; |
266 | 268 | import static com.facebook.presto.hive.HiveTableProperties.getEncryptTable; |
267 | 269 | import static com.facebook.presto.hive.HiveTableProperties.getExternalLocation; |
| 270 | +import static com.facebook.presto.hive.HiveTableProperties.getFooterSkipCount; |
| 271 | +import static com.facebook.presto.hive.HiveTableProperties.getHeaderSkipCount; |
268 | 272 | import static com.facebook.presto.hive.HiveTableProperties.getHiveStorageFormat; |
269 | 273 | import static com.facebook.presto.hive.HiveTableProperties.getOrcBloomFilterColumns; |
270 | 274 | import static com.facebook.presto.hive.HiveTableProperties.getOrcBloomFilterFpp; |
@@ -412,6 +416,9 @@ public class HiveMetadata |
412 | 416 | private static final String CSV_QUOTE_KEY = OpenCSVSerde.QUOTECHAR; |
413 | 417 | private static final String CSV_ESCAPE_KEY = OpenCSVSerde.ESCAPECHAR; |
414 | 418 |
|
| 419 | + public static final String SKIP_HEADER_COUNT_KEY = "skip.header.line.count"; |
| 420 | + public static final String SKIP_FOOTER_COUNT_KEY = "skip.footer.line.count"; |
| 421 | + |
415 | 422 | private static final JsonCodec<MaterializedViewDefinition> MATERIALIZED_VIEW_JSON_CODEC = jsonCodec(MaterializedViewDefinition.class); |
416 | 423 |
|
417 | 424 | private final boolean allowCorruptWritesForTesting; |
@@ -753,6 +760,12 @@ private ConnectorTableMetadata getTableMetadata(Optional<Table> table, SchemaTab |
753 | 760 | properties.put(AVRO_SCHEMA_URL, avroSchemaUrl); |
754 | 761 | } |
755 | 762 |
|
| 763 | + // Textfile and CSV specific properties |
| 764 | + getSerdeProperty(table.get(), SKIP_HEADER_COUNT_KEY) |
| 765 | + .ifPresent(skipHeaderCount -> properties.put(SKIP_HEADER_LINE_COUNT, Integer.valueOf(skipHeaderCount))); |
| 766 | + getSerdeProperty(table.get(), SKIP_FOOTER_COUNT_KEY) |
| 767 | + .ifPresent(skipFooterCount -> properties.put(SKIP_FOOTER_LINE_COUNT, Integer.valueOf(skipFooterCount))); |
| 768 | + |
756 | 769 | // CSV specific property |
757 | 770 | getCsvSerdeProperty(table.get(), CSV_SEPARATOR_KEY) |
758 | 771 | .ifPresent(csvSeparator -> properties.put(CSV_SEPARATOR, csvSeparator)); |
@@ -1294,6 +1307,28 @@ private Map<String, String> getEmptyTableProperties( |
1294 | 1307 | tableProperties.put(AVRO_SCHEMA_URL_KEY, validateAndNormalizeAvroSchemaUrl(avroSchemaUrl, hdfsContext)); |
1295 | 1308 | } |
1296 | 1309 |
|
| 1310 | + // Textfile and CSV specific properties |
| 1311 | + Set<HiveStorageFormat> csvAndTextFile = ImmutableSet.of(HiveStorageFormat.TEXTFILE, HiveStorageFormat.CSV); |
| 1312 | + getHeaderSkipCount(tableMetadata.getProperties()).ifPresent(headerSkipCount -> { |
| 1313 | + if (headerSkipCount > 0) { |
| 1314 | + checkFormatForProperty(hiveStorageFormat, csvAndTextFile, SKIP_HEADER_LINE_COUNT); |
| 1315 | + tableProperties.put(SKIP_HEADER_COUNT_KEY, String.valueOf(headerSkipCount)); |
| 1316 | + } |
| 1317 | + if (headerSkipCount < 0) { |
| 1318 | + throw new PrestoException(HIVE_INVALID_METADATA, format("Invalid value for %s property: %s", SKIP_HEADER_LINE_COUNT, headerSkipCount)); |
| 1319 | + } |
| 1320 | + }); |
| 1321 | + |
| 1322 | + getFooterSkipCount(tableMetadata.getProperties()).ifPresent(footerSkipCount -> { |
| 1323 | + if (footerSkipCount > 0) { |
| 1324 | + checkFormatForProperty(hiveStorageFormat, csvAndTextFile, SKIP_FOOTER_LINE_COUNT); |
| 1325 | + tableProperties.put(SKIP_FOOTER_COUNT_KEY, String.valueOf(footerSkipCount)); |
| 1326 | + } |
| 1327 | + if (footerSkipCount < 0) { |
| 1328 | + throw new PrestoException(HIVE_INVALID_METADATA, format("Invalid value for %s property: %s", SKIP_FOOTER_LINE_COUNT, footerSkipCount)); |
| 1329 | + } |
| 1330 | + }); |
| 1331 | + |
1297 | 1332 | // CSV specific properties |
1298 | 1333 | getCsvProperty(tableMetadata.getProperties(), CSV_ESCAPE) |
1299 | 1334 | .ifPresent(escape -> { |
@@ -1327,6 +1362,13 @@ private static void checkFormatForProperty(HiveStorageFormat actualStorageFormat |
1327 | 1362 | } |
1328 | 1363 | } |
1329 | 1364 |
|
| 1365 | + private static void checkFormatForProperty(HiveStorageFormat actualStorageFormat, Set<HiveStorageFormat> expectedStorageFormats, String propertyName) |
| 1366 | + { |
| 1367 | + if (!expectedStorageFormats.contains(actualStorageFormat)) { |
| 1368 | + throw new PrestoException(INVALID_TABLE_PROPERTY, format("Cannot specify %s table property for storage format: %s", propertyName, actualStorageFormat)); |
| 1369 | + } |
| 1370 | + } |
| 1371 | + |
1330 | 1372 | private String validateAndNormalizeAvroSchemaUrl(String url, HdfsContext context) |
1331 | 1373 | { |
1332 | 1374 | try { |
@@ -1647,7 +1689,17 @@ public HiveOutputTableHandle beginCreateTable(ConnectorSession session, Connecto |
1647 | 1689 | if (getAvroSchemaUrl(tableMetadata.getProperties()) != null) { |
1648 | 1690 | throw new PrestoException(NOT_SUPPORTED, "CREATE TABLE AS not supported when Avro schema url is set"); |
1649 | 1691 | } |
| 1692 | + getHeaderSkipCount(tableMetadata.getProperties()).ifPresent(headerSkipCount -> { |
| 1693 | + if (headerSkipCount > 1) { |
| 1694 | + throw new PrestoException(NOT_SUPPORTED, format("Creating Hive table with data with value of %s property greater than 0 is not supported", SKIP_HEADER_COUNT_KEY)); |
| 1695 | + } |
| 1696 | + }); |
1650 | 1697 |
|
| 1698 | + getFooterSkipCount(tableMetadata.getProperties()).ifPresent(footerSkipCount -> { |
| 1699 | + if (footerSkipCount > 0) { |
| 1700 | + throw new PrestoException(NOT_SUPPORTED, format("Creating Hive table with data with value of %s property greater than 0 is not supported", SKIP_FOOTER_COUNT_KEY)); |
| 1701 | + } |
| 1702 | + }); |
1651 | 1703 | HiveStorageFormat tableStorageFormat = getHiveStorageFormat(tableMetadata.getProperties()); |
1652 | 1704 | List<String> partitionedBy = getPartitionedBy(tableMetadata.getProperties()); |
1653 | 1705 | Optional<HiveBucketProperty> bucketProperty = getBucketProperty(tableMetadata.getProperties()); |
@@ -2016,6 +2068,15 @@ private HiveInsertTableHandle beginInsertInternal(ConnectorSession session, Conn |
2016 | 2068 | locationHandle = locationService.forExistingTable(metastore, session, table, tempPathRequired); |
2017 | 2069 | } |
2018 | 2070 |
|
| 2071 | + Optional.ofNullable(table.getParameters().get(SKIP_HEADER_COUNT_KEY)).map(Integer::parseInt).ifPresent(headerSkipCount -> { |
| 2072 | + if (headerSkipCount > 1) { |
| 2073 | + throw new PrestoException(NOT_SUPPORTED, format("INSERT into %s Hive table with value of %s property greater than 1 is not supported", tableName, SKIP_HEADER_COUNT_KEY)); |
| 2074 | + } |
| 2075 | + }); |
| 2076 | + if (table.getParameters().containsKey(SKIP_FOOTER_COUNT_KEY)) { |
| 2077 | + throw new PrestoException(NOT_SUPPORTED, format("INSERT into %s Hive table with %s property not supported", tableName, SKIP_FOOTER_COUNT_KEY)); |
| 2078 | + } |
| 2079 | + |
2019 | 2080 | Optional<? extends TableEncryptionProperties> tableEncryptionProperties = getTableEncryptionPropertiesFromHiveProperties(table.getParameters(), tableStorageFormat); |
2020 | 2081 |
|
2021 | 2082 | HiveStorageFormat partitionStorageFormat = isRespectTableFormat(session) ? tableStorageFormat : getHiveStorageFormat(session); |
|
0 commit comments