You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@avro.apache.org by dk...@apache.org on 2018/11/29 21:24:51 UTC
[avro] branch master updated: C: Allow record to have no fields.
This is an automated email from the ASF dual-hosted git repository.
dkulp pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/avro.git
The following commit(s) were added to refs/heads/master by this push:
new b07dfbc C: Allow record to have no fields.
b07dfbc is described below
commit b07dfbcc6c37da1b730a4bd897d4cfdeabe63cdc
Author: Ben Walsh <be...@byhiras.com>
AuthorDate: Tue Aug 20 08:41:46 2013 +0000
C: Allow record to have no fields.
---
lang/c/src/avro_generic_internal.h | 2 +-
lang/c/src/datafile.c | 10 +-
lang/c/src/generic.c | 54 ++++++----
lang/c/src/schema.c | 4 -
lang/c/tests/CMakeLists.txt | 1 +
lang/c/tests/schema_tests/pass/record_no_fields | 1 +
lang/c/tests/test_avro_1904.c | 130 ++++++++++++++++++++++++
7 files changed, 171 insertions(+), 31 deletions(-)
diff --git a/lang/c/src/avro_generic_internal.h b/lang/c/src/avro_generic_internal.h
index dec7652..dd6d52d 100644
--- a/lang/c/src/avro_generic_internal.h
+++ b/lang/c/src/avro_generic_internal.h
@@ -60,7 +60,7 @@ typedef struct avro_generic_value_iface {
#define avro_value_instance_size(gcls) \
- ((gcls)->instance_size == NULL? 0: (gcls)->instance_size(&(gcls)->parent))
+ ((gcls)->instance_size == NULL ? (ssize_t)-1 : (ssize_t)(gcls)->instance_size(&(gcls)->parent))
#define avro_value_init(gcls, self) \
((gcls)->init == NULL? EINVAL: (gcls)->init(&(gcls)->parent, (self)))
#define avro_value_done(gcls, self) \
diff --git a/lang/c/src/datafile.c b/lang/c/src/datafile.c
index f2da603..95096c1 100644
--- a/lang/c/src/datafile.c
+++ b/lang/c/src/datafile.c
@@ -460,11 +460,13 @@ static int file_read_block_count(avro_file_reader_t r)
r->current_blocklen = len;
}
- check_prefix(rval, avro_read(r->reader, r->current_blockdata, len),
- "Cannot read file block: ");
+ if (len > 0) {
+ check_prefix(rval, avro_read(r->reader, r->current_blockdata, len),
+ "Cannot read file block: ");
- check_prefix(rval, avro_codec_decode(r->codec, r->current_blockdata, len),
- "Cannot decode file block: ");
+ check_prefix(rval, avro_codec_decode(r->codec, r->current_blockdata, len),
+ "Cannot decode file block: ");
+ }
avro_reader_memory_set_source(r->block_reader, (const char *) r->codec->block_data, r->codec->used_size);
diff --git a/lang/c/src/generic.c b/lang/c/src/generic.c
index ddef81a..5f957b7 100644
--- a/lang/c/src/generic.c
+++ b/lang/c/src/generic.c
@@ -551,16 +551,21 @@ avro_generic_link_init(const avro_value_iface_t *viface, void *vself)
container_of(viface, avro_generic_link_value_iface_t, parent.parent);
avro_value_t *self = (avro_value_t *) vself;
- size_t target_instance_size =
+ ssize_t target_instance_size =
avro_value_instance_size(iface->target_giface);
- if (target_instance_size == 0) {
+ if (target_instance_size < 0) {
return EINVAL;
}
self->iface = &iface->target_giface->parent;
- self->self = avro_malloc(target_instance_size);
- if (self->self == NULL) {
- return ENOMEM;
+
+ if (target_instance_size == 0) {
+ self->self = NULL;
+ } else {
+ self->self = avro_malloc(target_instance_size);
+ if (self->self == NULL) {
+ return ENOMEM;
+ }
}
rval = avro_value_init(iface->target_giface, self->self);
@@ -2124,8 +2129,8 @@ avro_generic_array_class(avro_schema_t schema, memoize_state_t *state)
return NULL;
}
- size_t child_size = avro_value_instance_size(child_giface);
- if (child_size == 0) {
+ ssize_t child_size = avro_value_instance_size(child_giface);
+ if (child_size < 0) {
avro_set_error("Array item class must provide instance_size");
avro_value_iface_decref(&child_giface->parent);
return NULL;
@@ -2780,8 +2785,8 @@ avro_generic_map_class(avro_schema_t schema, memoize_state_t *state)
return NULL;
}
- size_t child_size = avro_value_instance_size(child_giface);
- if (child_size == 0) {
+ ssize_t child_size = avro_value_instance_size(child_giface);
+ if (child_size < 0) {
avro_set_error("Map value class must provide instance_size");
avro_value_iface_decref(&child_giface->parent);
return NULL;
@@ -3103,14 +3108,19 @@ avro_generic_record_class(avro_schema_t schema, memoize_state_t *state)
size_t field_ifaces_size =
sizeof(avro_generic_value_iface_t *) * iface->field_count;
- iface->field_offsets = (size_t *) avro_malloc(field_offsets_size);
- if (iface->field_offsets == NULL) {
- goto error;
- }
+ if (iface->field_count == 0) {
+ iface->field_offsets = NULL;
+ iface->field_ifaces = NULL;
+ } else {
+ iface->field_offsets = (size_t *) avro_malloc(field_offsets_size);
+ if (iface->field_offsets == NULL) {
+ goto error;
+ }
- iface->field_ifaces = (avro_generic_value_iface_t **) avro_malloc(field_ifaces_size);
- if (iface->field_ifaces == NULL) {
- goto error;
+ iface->field_ifaces = (avro_generic_value_iface_t **) avro_malloc(field_ifaces_size);
+ if (iface->field_ifaces == NULL) {
+ goto error;
+ }
}
size_t next_offset = sizeof(avro_generic_record_t);
@@ -3139,9 +3149,9 @@ avro_generic_record_class(avro_schema_t schema, memoize_state_t *state)
goto error;
}
- size_t field_size =
+ ssize_t field_size =
avro_value_instance_size(iface->field_ifaces[i]);
- if (field_size == 0) {
+ if (field_size < 0) {
avro_set_error("Record field class must provide instance_size");
goto error;
}
@@ -3506,9 +3516,9 @@ avro_generic_union_class(avro_schema_t schema, memoize_state_t *state)
goto error;
}
- size_t branch_size =
+ ssize_t branch_size =
avro_value_instance_size(iface->branch_ifaces[i]);
- if (branch_size == 0) {
+ if (branch_size < 0) {
avro_set_error("Union branch class must provide instance_size");
goto error;
}
@@ -3518,8 +3528,8 @@ avro_generic_union_class(avro_schema_t schema, memoize_state_t *state)
i, branch_size);
#endif
- if (branch_size > max_branch_size) {
- max_branch_size = branch_size;
+ if ((size_t)branch_size > max_branch_size) {
+ max_branch_size = (size_t)branch_size;
}
}
diff --git a/lang/c/src/schema.c b/lang/c/src/schema.c
index a78f733..7a82c2e 100644
--- a/lang/c/src/schema.c
+++ b/lang/c/src/schema.c
@@ -919,10 +919,6 @@ avro_schema_from_json_t(json_t *json, avro_schema_t *schema,
return EINVAL;
}
num_fields = json_array_size(json_fields);
- if (num_fields == 0) {
- avro_set_error("Record type must have at least one field");
- return EINVAL;
- }
fullname = json_string_value(json_name);
if (!fullname) {
avro_set_error("Record type must have a \"name\"");
diff --git a/lang/c/tests/CMakeLists.txt b/lang/c/tests/CMakeLists.txt
index 445e689..c66f67c 100644
--- a/lang/c/tests/CMakeLists.txt
+++ b/lang/c/tests/CMakeLists.txt
@@ -64,3 +64,4 @@ add_avro_test(test_refcount)
add_avro_test(test_cpp test_cpp.cpp)
add_avro_test(test_avro_1379)
add_avro_test(test_avro_1691)
+add_avro_test(test_avro_1904)
diff --git a/lang/c/tests/schema_tests/pass/record_no_fields b/lang/c/tests/schema_tests/pass/record_no_fields
new file mode 100644
index 0000000..142f452
--- /dev/null
+++ b/lang/c/tests/schema_tests/pass/record_no_fields
@@ -0,0 +1 @@
+{"type": "record", "name": "R", "fields": []}
diff --git a/lang/c/tests/test_avro_1904.c b/lang/c/tests/test_avro_1904.c
new file mode 100644
index 0000000..ac20e20
--- /dev/null
+++ b/lang/c/tests/test_avro_1904.c
@@ -0,0 +1,130 @@
+/*
+ * 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 <stdio.h>
+#include <sys/stat.h>
+#include "avro.h"
+
+#define NUM_RECORDS 100
+
+static const char *filename = "avro_file.dat";
+
+static const char PERSON_SCHEMA[] =
+ "{"
+ " \"type\":\"record\","
+ " \"name\":\"Person\","
+ " \"fields\": ["
+ " ]"
+ "}";
+
+static int read_data() {
+ int rval;
+ int records_read = 0;
+
+ avro_file_reader_t reader;
+ avro_value_iface_t *iface;
+ avro_value_t value;
+
+ fprintf(stderr, "\nReading...\n");
+
+ rval = avro_file_reader(filename, &reader);
+
+ if (rval) {
+ fprintf(stderr, "Error: %s\n", avro_strerror());
+ return EXIT_FAILURE;
+ }
+
+ avro_schema_t schema = avro_file_reader_get_writer_schema(reader);
+
+ iface = avro_generic_class_from_schema(schema);
+ avro_generic_value_new(iface, &value);
+
+ while ((rval = avro_file_reader_read_value(reader, &value)) == 0) {
+ records_read++;
+ avro_value_reset(&value);
+ }
+
+ avro_value_decref(&value);
+ avro_value_iface_decref(iface);
+ avro_schema_decref(schema);
+ avro_file_reader_close(reader);
+
+ fprintf(stderr, "read %d records.\n", records_read);
+
+ if (rval != EOF || records_read != NUM_RECORDS) {
+ fprintf(stderr, "Error: %s\n", avro_strerror());
+ return EXIT_FAILURE;
+ }
+
+ return EXIT_SUCCESS;
+}
+
+static int write_data() {
+ int i;
+ avro_schema_t schema;
+ avro_schema_error_t error;
+ avro_file_writer_t writer;
+ avro_value_iface_t *iface;
+ avro_value_t value;
+
+ fprintf(stderr, "\nWriting...\n");
+
+ if (avro_schema_from_json(PERSON_SCHEMA, 0, &schema, &error)) {
+ fprintf(stderr, "Unable to parse schema\n");
+ return EXIT_FAILURE;
+ }
+
+ iface = avro_generic_class_from_schema(schema);
+ avro_generic_value_new(iface, &value);
+
+ if (avro_file_writer_create(filename, schema, &writer)) {
+ fprintf(stderr, "There was an error creating file: %s\n", avro_strerror());
+ return EXIT_FAILURE;
+ }
+
+ for (i = 0; i < NUM_RECORDS; i++) {
+ if (avro_file_writer_append_value(writer, &value)) {
+ fprintf(stderr, "There was an error creating file: %s\n", avro_strerror());
+ return EXIT_FAILURE;
+ }
+ }
+
+ if (avro_file_writer_close(writer)) {
+ fprintf(stderr, "There was an error creating file: %s\n", avro_strerror());
+ return EXIT_FAILURE;
+ }
+
+ avro_value_iface_decref(iface);
+ avro_value_decref(&value);
+ avro_schema_decref(schema);
+
+ return EXIT_SUCCESS;
+}
+
+int main()
+{
+ int read_data_result;
+
+ if (write_data()) {
+ return EXIT_FAILURE;
+ }
+
+ read_data_result = read_data();
+ remove(filename);
+
+ return read_data_result;
+}