Branch data Line data Source code
1 : : /* Copyright (c) 2009, 2010, 2011, 2016 Nicira, Inc.
2 : : *
3 : : * Licensed under the Apache License, Version 2.0 (the "License");
4 : : * you may not use this file except in compliance with the License.
5 : : * You may obtain a copy of the License at:
6 : : *
7 : : * http://www.apache.org/licenses/LICENSE-2.0
8 : : *
9 : : * Unless required by applicable law or agreed to in writing, software
10 : : * distributed under the License is distributed on an "AS IS" BASIS,
11 : : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 : : * See the License for the specific language governing permissions and
13 : : * limitations under the License.
14 : : */
15 : :
16 : : #include <config.h>
17 : :
18 : : #include "ovsdb/column.h"
19 : :
20 : : #include <stdlib.h>
21 : :
22 : : #include "column.h"
23 : : #include "openvswitch/dynamic-string.h"
24 : : #include "openvswitch/json.h"
25 : : #include "ovsdb-error.h"
26 : : #include "ovsdb-parser.h"
27 : : #include "table.h"
28 : : #include "util.h"
29 : :
30 : : struct ovsdb_column *
31 : 336096 : ovsdb_column_create(const char *name,
32 : : bool mutable, bool persistent,
33 : : const struct ovsdb_type *type)
34 : : {
35 : : /* Doesn't set the new column's 'index': the caller must do that. */
36 : : struct ovsdb_column *column;
37 : :
38 : 336096 : column = xzalloc(sizeof *column);
39 : 336096 : column->name = xstrdup(name);
40 : 336096 : column->mutable = mutable;
41 : 336096 : column->persistent = persistent;
42 : 336096 : ovsdb_type_clone(&column->type, type);
43 : :
44 : 336096 : return column;
45 : : }
46 : :
47 : : struct ovsdb_column *
48 : 3 : ovsdb_column_clone(const struct ovsdb_column *old)
49 : : {
50 : : /* Doesn't copy the column's 'index': the caller must do that. */
51 : 3 : return ovsdb_column_create(old->name,
52 : 6 : old->mutable, old->persistent,
53 : : &old->type);
54 : : }
55 : :
56 : : void
57 : 335577 : ovsdb_column_destroy(struct ovsdb_column *column)
58 : : {
59 : 335577 : ovsdb_type_destroy(&column->type);
60 : 335577 : free(column->name);
61 : 335577 : free(column);
62 : 335577 : }
63 : :
64 : : struct ovsdb_error *
65 : 274179 : ovsdb_column_from_json(const struct json *json, const char *name,
66 : : struct ovsdb_column **columnp)
67 : : {
68 : : const struct json *mutable_json, *ephemeral, *type_json;
69 : : struct ovsdb_error *error;
70 : : struct ovsdb_type type;
71 : : struct ovsdb_parser parser;
72 : :
73 : 274179 : *columnp = NULL;
74 : :
75 : 274179 : ovsdb_parser_init(&parser, json, "schema for column %s", name);
76 : 274179 : mutable_json = ovsdb_parser_member(&parser, "mutable",
77 : : OP_TRUE | OP_FALSE | OP_OPTIONAL);
78 : 274179 : ephemeral = ovsdb_parser_member(&parser, "ephemeral",
79 : : OP_TRUE | OP_FALSE | OP_OPTIONAL);
80 : 274179 : type_json = ovsdb_parser_member(&parser, "type", OP_STRING | OP_OBJECT);
81 : 274179 : error = ovsdb_parser_finish(&parser);
82 [ - + ]: 274179 : if (error) {
83 : 0 : return error;
84 : : }
85 : :
86 : 274179 : error = ovsdb_type_from_json(&type, type_json);
87 [ - + ]: 274179 : if (error) {
88 : 0 : return error;
89 : : }
90 : :
91 [ + + ][ - + ]: 274179 : bool mutable = !mutable_json || json_boolean(mutable_json);
92 [ + + ]: 274179 : if (!mutable
93 [ + + - + ]: 9495 : && (ovsdb_base_type_is_weak_ref(&type.key) ||
94 : 4747 : ovsdb_base_type_is_weak_ref(&type.value))) {
95 : : /* We cannot allow a weak reference to be immutable: if referenced rows
96 : : * are deleted, then the weak reference needs to change. */
97 : 1 : mutable = true;
98 : : }
99 : :
100 [ + + ]: 274179 : bool persistent = ephemeral ? !json_boolean(ephemeral) : true;
101 : 274179 : *columnp = ovsdb_column_create(name, mutable, persistent, &type);
102 : :
103 : 274179 : ovsdb_type_destroy(&type);
104 : :
105 : 274179 : return NULL;
106 : : }
107 : :
108 : : struct json *
109 : 1121345 : ovsdb_column_to_json(const struct ovsdb_column *column)
110 : : {
111 : 1121345 : struct json *json = json_object_create();
112 [ + + ]: 1121345 : if (!column->mutable) {
113 : 19987 : json_object_put(json, "mutable", json_boolean_create(false));
114 : : }
115 [ + + ]: 1121345 : if (!column->persistent) {
116 : 185612 : json_object_put(json, "ephemeral", json_boolean_create(true));
117 : : }
118 : 1121345 : json_object_put(json, "type", ovsdb_type_to_json(&column->type));
119 : 1121345 : return json;
120 : : }
121 : :
122 : : void
123 : 42136 : ovsdb_column_set_init(struct ovsdb_column_set *set)
124 : : {
125 : 42136 : set->columns = NULL;
126 : 42136 : set->n_columns = set->allocated_columns = 0;
127 : 42136 : }
128 : :
129 : : void
130 : 117118 : ovsdb_column_set_destroy(struct ovsdb_column_set *set)
131 : : {
132 : 117118 : free(set->columns);
133 : 117118 : }
134 : :
135 : : void
136 : 56476 : ovsdb_column_set_clone(struct ovsdb_column_set *new,
137 : : const struct ovsdb_column_set *old)
138 : : {
139 : 56476 : new->columns = xmemdup(old->columns,
140 : 56476 : old->n_columns * sizeof *old->columns);
141 : 56476 : new->n_columns = new->allocated_columns = old->n_columns;
142 : 56476 : }
143 : :
144 : : struct ovsdb_error *
145 : 41787 : ovsdb_column_set_from_json(const struct json *json,
146 : : const struct ovsdb_table_schema *schema,
147 : : struct ovsdb_column_set *set)
148 : : {
149 : 41787 : ovsdb_column_set_init(set);
150 [ + + ]: 41787 : if (!json) {
151 : : struct shash_node *node;
152 : :
153 [ + + ][ - + ]: 38016 : SHASH_FOR_EACH (node, &schema->columns) {
154 : 35537 : const struct ovsdb_column *column = node->data;
155 : 35537 : ovsdb_column_set_add(set, column);
156 : : }
157 : :
158 : 2479 : return NULL;
159 : : } else {
160 : 39308 : struct ovsdb_error *error = NULL;
161 : : size_t i;
162 : :
163 [ - + ]: 39308 : if (json->type != JSON_ARRAY) {
164 : 0 : goto error;
165 : : }
166 : :
167 : : /* XXX this is O(n**2) */
168 [ + + ]: 81207 : for (i = 0; i < json->u.array.n; i++) {
169 : : const struct ovsdb_column *column;
170 : : const char *s;
171 : :
172 [ + + ]: 41901 : if (json->u.array.elems[i]->type != JSON_STRING) {
173 : 1 : goto error;
174 : : }
175 : :
176 : 41900 : s = json->u.array.elems[i]->u.string;
177 : 41900 : column = shash_find_data(&schema->columns, s);
178 [ + + ]: 41900 : if (!column) {
179 : 1 : error = ovsdb_syntax_error(json, NULL, "%s is not a valid "
180 : : "column name", s);
181 : 1 : goto error;
182 [ - + ]: 41899 : } else if (ovsdb_column_set_contains(set, column->index)) {
183 : 0 : goto error;
184 : : }
185 : 41899 : ovsdb_column_set_add(set, column);
186 : : }
187 : 39306 : return NULL;
188 : :
189 : : error:
190 : 2 : ovsdb_column_set_destroy(set);
191 : 2 : ovsdb_column_set_init(set);
192 [ + + ]: 2 : if (!error) {
193 : 1 : error = ovsdb_syntax_error(json, NULL, "array of distinct column "
194 : : "names expected");
195 : : }
196 : 2 : return error;
197 : : }
198 : : }
199 : :
200 : : struct json *
201 : 39048 : ovsdb_column_set_to_json(const struct ovsdb_column_set *set)
202 : : {
203 : : struct json *json;
204 : : size_t i;
205 : :
206 : 39048 : json = json_array_create_empty();
207 [ + + ]: 86504 : for (i = 0; i < set->n_columns; i++) {
208 : 47456 : json_array_add(json, json_string_create(set->columns[i]->name));
209 : : }
210 : 39048 : return json;
211 : : }
212 : :
213 : : /* Returns an English string listing the contents of 'set', e.g. "columns
214 : : * \"a\", \"b\", and \"c\"". The caller must free the string. */
215 : : char *
216 : 21 : ovsdb_column_set_to_string(const struct ovsdb_column_set *set)
217 : : {
218 [ - + ]: 21 : if (!set->n_columns) {
219 : 0 : return xstrdup("no columns");
220 : : } else {
221 : : struct ds s;
222 : : size_t i;
223 : :
224 : 21 : ds_init(&s);
225 [ - + ]: 21 : ds_put_format(&s, "column%s ", set->n_columns > 1 ? "s" : "");
226 [ + + ]: 42 : for (i = 0; i < set->n_columns; i++) {
227 : 21 : const char *delimiter = english_list_delimiter(i, set->n_columns);
228 : 21 : ds_put_format(&s, "%s\"%s\"", delimiter, set->columns[i]->name);
229 : : }
230 : 21 : return ds_steal_cstr(&s);
231 : : }
232 : : }
233 : :
234 : : void
235 : 128957 : ovsdb_column_set_add(struct ovsdb_column_set *set,
236 : : const struct ovsdb_column *column)
237 : : {
238 [ + + ]: 128957 : if (set->n_columns >= set->allocated_columns) {
239 : 89401 : set->columns = x2nrealloc(set->columns, &set->allocated_columns,
240 : : sizeof *set->columns);
241 : : }
242 : 128957 : set->columns[set->n_columns++] = column;
243 : 128957 : }
244 : :
245 : : void
246 : 32 : ovsdb_column_set_add_all(struct ovsdb_column_set *set,
247 : : const struct ovsdb_table *table)
248 : : {
249 : : struct shash_node *node;
250 : :
251 [ + + ][ - + ]: 168 : SHASH_FOR_EACH (node, &table->schema->columns) {
252 : 136 : const struct ovsdb_column *column = node->data;
253 : 136 : ovsdb_column_set_add(set, column);
254 : : }
255 : 32 : }
256 : :
257 : : bool
258 : 44688 : ovsdb_column_set_contains(const struct ovsdb_column_set *set,
259 : : unsigned int column_index)
260 : : {
261 : : size_t i;
262 : :
263 [ + + ]: 52061 : for (i = 0; i < set->n_columns; i++) {
264 [ + + ]: 7682 : if (set->columns[i]->index == column_index) {
265 : 309 : return true;
266 : : }
267 : : }
268 : 44379 : return false;
269 : : }
270 : :
271 : : /* This comparison is sensitive to ordering of columns within a set, but that's
272 : : * good: the only existing caller wants to make sure that hash values are
273 : : * comparable, which is only true if column ordering is the same. */
274 : : bool
275 : 0 : ovsdb_column_set_equals(const struct ovsdb_column_set *a,
276 : : const struct ovsdb_column_set *b)
277 : : {
278 : : size_t i;
279 : :
280 [ # # ]: 0 : if (a->n_columns != b->n_columns) {
281 : 0 : return false;
282 : : }
283 [ # # ]: 0 : for (i = 0; i < a->n_columns; i++) {
284 [ # # ]: 0 : if (a->columns[i] != b->columns[i]) {
285 : 0 : return false;
286 : : }
287 : : }
288 : 0 : return true;
289 : : }
|