| // Licensed to the Apache Software Foundation (ASF) under one |
| // or more contributor license agreements. See the NOTICE file |
| // distributed with this work for additional information |
| // regarding copyright ownership. The ASF licenses this file |
| // to you under the Apache License, Version 2.0 (the |
| // "License"); you may not use this file except in compliance |
| // with the License. You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, |
| // software distributed under the License is distributed on an |
| // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| // KIND, either express or implied. See the License for the |
| // specific language governing permissions and limitations |
| // under the License. |
| |
| #include "util/avro-util.h" |
| |
| #include <avro/schema.h> |
| #include <sstream> |
| |
| using namespace std; |
| |
| namespace impala { |
| |
| const char* AvroSchemaElement::LLVM_CLASS_NAME = "struct.impala::AvroSchemaElement"; |
| |
| bool IsSupportedAvroType(const avro_schema_t& schema) { |
| switch (schema->type) { |
| case AVRO_STRING: |
| case AVRO_BYTES: |
| case AVRO_INT32: |
| case AVRO_DATE: |
| case AVRO_INT64: |
| case AVRO_FLOAT: |
| case AVRO_DOUBLE: |
| case AVRO_BOOLEAN: |
| case AVRO_NULL: |
| case AVRO_RECORD: |
| case AVRO_DECIMAL: |
| return true; |
| default: |
| return false; |
| } |
| } |
| |
| Status AvroSchemaElement::ConvertSchema( |
| const avro_schema_t& schema, AvroSchemaElement* element) { |
| element->schema = schema; |
| |
| // Look for special case of [<supported type>, "null"] union |
| if (element->schema->type == AVRO_UNION) { |
| int num_fields = avro_schema_union_size(schema); |
| DCHECK_GT(num_fields, 0); |
| if (num_fields == 2) { |
| const avro_schema_t& child0 = avro_schema_union_branch(schema, 0); |
| const avro_schema_t& child1 = avro_schema_union_branch(schema, 1); |
| int null_position = -1; |
| if (child0->type == AVRO_NULL) { |
| null_position = 0; |
| } else if (child1->type == AVRO_NULL) { |
| null_position = 1; |
| } |
| |
| if (null_position != -1) { |
| const avro_schema_t& non_null_child = null_position == 0 ? child1 : child0; |
| AvroSchemaElement child; |
| RETURN_IF_ERROR(ConvertSchema(non_null_child, &child)); |
| |
| // 'schema' is a [<child>, "null"] union. Treat this node as the same type as |
| // child except with null_union_position set appropriately. |
| DCHECK_EQ(child.null_union_position, -1) |
| << "Avro spec does not allow immediately nested unions"; |
| *element = child; |
| element->null_union_position = null_position; |
| return Status::OK(); |
| } |
| } |
| } |
| |
| if (!IsSupportedAvroType(element->schema)) { |
| stringstream ss; |
| ss << "Avro enum, array, map, union, and fixed types are not supported. " |
| << "Got type: " << avro_type_name(element->schema->type); |
| return Status(ss.str()); |
| } |
| |
| if (element->schema->type == AVRO_RECORD) { |
| int num_fields = avro_schema_record_size(element->schema); |
| element->children.resize(num_fields); |
| for (int i = 0; i < num_fields; ++i) { |
| avro_schema_t field = |
| avro_schema_record_field_get_by_index(element->schema, i); |
| RETURN_IF_ERROR(ConvertSchema(field, &element->children[i])); |
| } |
| } |
| return Status::OK(); |
| } |
| |
| ScopedAvroSchemaElement::~ScopedAvroSchemaElement() { |
| // avro_schema_decref can handle NULL. If element_.schema is a record or other complex |
| // type, it will recursively decref it's children when it's free. |
| avro_schema_decref(element_.schema); |
| } |
| |
| Status AvroSchemaToColumnType( |
| const avro_schema_t& schema, const string& column_name, ColumnType* column_type) { |
| switch (schema->type) { |
| case AVRO_BYTES: |
| case AVRO_STRING: |
| *column_type = TYPE_STRING; |
| return Status::OK(); |
| case AVRO_INT32: |
| *column_type = TYPE_INT; |
| return Status::OK(); |
| case AVRO_DATE: |
| *column_type = TYPE_DATE; |
| return Status::OK(); |
| case AVRO_INT64: |
| *column_type = TYPE_BIGINT; |
| return Status::OK(); |
| case AVRO_FLOAT: |
| *column_type = TYPE_FLOAT; |
| return Status::OK(); |
| case AVRO_DOUBLE: |
| *column_type = TYPE_DOUBLE; |
| return Status::OK(); |
| case AVRO_BOOLEAN: |
| *column_type = TYPE_BOOLEAN; |
| return Status::OK(); |
| case AVRO_DECIMAL: { |
| int precision = avro_schema_decimal_precision(schema); |
| int scale = avro_schema_decimal_scale(schema); |
| if (!ColumnType::ValidateDecimalParams(precision, scale)) { |
| return Status(TErrorCode::AVRO_INVALID_DECIMAL, column_name, precision, scale); |
| } |
| *column_type = ColumnType::CreateDecimalType(precision, scale); |
| return Status::OK(); |
| } |
| default: |
| return Status(TErrorCode::AVRO_UNSUPPORTED_TYPE, column_name, avro_type_name(schema->type)); |
| } |
| } |
| } |