LCOV - code coverage report
Current view: top level - ovsdb - execution.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 303 326 92.9 %
Date: 2016-09-14 01:02:56 Functions: 17 18 94.4 %
Branches: 119 164 72.6 %

           Branch data     Line data    Source code
       1                 :            : /* Copyright (c) 2009, 2010, 2011, 2012, 2013 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 <limits.h>
      19                 :            : 
      20                 :            : #include "column.h"
      21                 :            : #include "condition.h"
      22                 :            : #include "file.h"
      23                 :            : #include "openvswitch/json.h"
      24                 :            : #include "mutation.h"
      25                 :            : #include "ovsdb-data.h"
      26                 :            : #include "ovsdb-error.h"
      27                 :            : #include "ovsdb-parser.h"
      28                 :            : #include "ovsdb.h"
      29                 :            : #include "query.h"
      30                 :            : #include "row.h"
      31                 :            : #include "server.h"
      32                 :            : #include "table.h"
      33                 :            : #include "timeval.h"
      34                 :            : #include "transaction.h"
      35                 :            : 
      36                 :            : struct ovsdb_execution {
      37                 :            :     struct ovsdb *db;
      38                 :            :     const struct ovsdb_session *session;
      39                 :            :     struct ovsdb_txn *txn;
      40                 :            :     struct ovsdb_symbol_table *symtab;
      41                 :            :     bool durable;
      42                 :            : 
      43                 :            :     /* Triggers. */
      44                 :            :     long long int elapsed_msec;
      45                 :            :     long long int timeout_msec;
      46                 :            : };
      47                 :            : 
      48                 :            : typedef struct ovsdb_error *ovsdb_operation_executor(struct ovsdb_execution *,
      49                 :            :                                                      struct ovsdb_parser *,
      50                 :            :                                                      struct json *result);
      51                 :            : 
      52                 :            : static ovsdb_operation_executor ovsdb_execute_insert;
      53                 :            : static ovsdb_operation_executor ovsdb_execute_select;
      54                 :            : static ovsdb_operation_executor ovsdb_execute_update;
      55                 :            : static ovsdb_operation_executor ovsdb_execute_mutate;
      56                 :            : static ovsdb_operation_executor ovsdb_execute_delete;
      57                 :            : static ovsdb_operation_executor ovsdb_execute_wait;
      58                 :            : static ovsdb_operation_executor ovsdb_execute_commit;
      59                 :            : static ovsdb_operation_executor ovsdb_execute_abort;
      60                 :            : static ovsdb_operation_executor ovsdb_execute_comment;
      61                 :            : static ovsdb_operation_executor ovsdb_execute_assert;
      62                 :            : 
      63                 :            : static ovsdb_operation_executor *
      64                 :      78092 : lookup_executor(const char *name, bool *read_only)
      65                 :            : {
      66                 :            :     struct ovsdb_operation {
      67                 :            :         const char *name;
      68                 :            :         bool read_only;
      69                 :            :         ovsdb_operation_executor *executor;
      70                 :            :     };
      71                 :            : 
      72                 :            :     static const struct ovsdb_operation operations[] = {
      73                 :            :         { "insert", false, ovsdb_execute_insert },
      74                 :            :         { "select", true, ovsdb_execute_select },
      75                 :            :         { "update", false, ovsdb_execute_update },
      76                 :            :         { "mutate", false, ovsdb_execute_mutate },
      77                 :            :         { "delete", false, ovsdb_execute_delete },
      78                 :            :         { "wait", true, ovsdb_execute_wait },
      79                 :            :         { "commit", false, ovsdb_execute_commit },
      80                 :            :         { "abort", true, ovsdb_execute_abort },
      81                 :            :         { "comment", true, ovsdb_execute_comment },
      82                 :            :         { "assert", true, ovsdb_execute_assert },
      83                 :            :     };
      84                 :            : 
      85                 :            :     size_t i;
      86                 :            : 
      87         [ +  - ]:     345891 :     for (i = 0; i < ARRAY_SIZE(operations); i++) {
      88                 :     345891 :         const struct ovsdb_operation *c = &operations[i];
      89         [ +  + ]:     345891 :         if (!strcmp(c->name, name)) {
      90                 :      78092 :             *read_only = c->read_only;
      91                 :      78092 :             return c->executor;
      92                 :            :         }
      93                 :            :     }
      94                 :          0 :     return NULL;
      95                 :            : }
      96                 :            : 
      97                 :            : struct json *
      98                 :      12583 : ovsdb_execute(struct ovsdb *db, const struct ovsdb_session *session,
      99                 :            :               const struct json *params, bool read_only,
     100                 :            :               long long int elapsed_msec, long long int *timeout_msec)
     101                 :            : {
     102                 :            :     struct ovsdb_execution x;
     103                 :            :     struct ovsdb_error *error;
     104                 :            :     struct json *results;
     105                 :            :     size_t n_operations;
     106                 :            :     size_t i;
     107                 :            : 
     108         [ +  - ]:      12583 :     if (params->type != JSON_ARRAY
     109         [ +  - ]:      12583 :         || !params->u.array.n
     110         [ +  - ]:      12583 :         || params->u.array.elems[0]->type != JSON_STRING
     111         [ -  + ]:      12583 :         || strcmp(params->u.array.elems[0]->u.string, db->schema->name)) {
     112         [ #  # ]:          0 :         if (params->type != JSON_ARRAY) {
     113                 :          0 :             error = ovsdb_syntax_error(params, NULL, "array expected");
     114                 :            :         } else {
     115                 :          0 :             error = ovsdb_syntax_error(params, NULL, "database name expected "
     116                 :            :                                        "as first parameter");
     117                 :            :         }
     118                 :            : 
     119                 :          0 :         results = ovsdb_error_to_json(error);
     120                 :          0 :         ovsdb_error_destroy(error);
     121                 :          0 :         return results;
     122                 :            :     }
     123                 :            : 
     124                 :      12583 :     x.db = db;
     125                 :      12583 :     x.session = session;
     126                 :      12583 :     x.txn = ovsdb_txn_create(db);
     127                 :      12583 :     x.symtab = ovsdb_symbol_table_create();
     128                 :      12583 :     x.durable = false;
     129                 :      12583 :     x.elapsed_msec = elapsed_msec;
     130                 :      12583 :     x.timeout_msec = LLONG_MAX;
     131                 :      12583 :     results = NULL;
     132                 :            : 
     133                 :      12583 :     results = json_array_create_empty();
     134                 :      12583 :     n_operations = params->u.array.n - 1;
     135                 :      12583 :     error = NULL;
     136         [ +  + ]:      90577 :     for (i = 1; i <= n_operations; i++) {
     137                 :      78092 :         struct json *operation = params->u.array.elems[i];
     138                 :            :         struct ovsdb_error *parse_error;
     139                 :            :         struct ovsdb_parser parser;
     140                 :            :         struct json *result;
     141                 :            :         const struct json *op;
     142                 :      78092 :         const char *op_name = NULL;
     143                 :      78092 :         bool ro = false;
     144                 :            : 
     145                 :            :         /* Parse and execute operation. */
     146                 :      78092 :         ovsdb_parser_init(&parser, operation,
     147                 :            :                           "ovsdb operation %"PRIuSIZE" of %"PRIuSIZE, i,
     148                 :            :                           n_operations);
     149                 :      78092 :         op = ovsdb_parser_member(&parser, "op", OP_ID);
     150                 :      78092 :         result = json_object_create();
     151         [ +  - ]:      78092 :         if (op) {
     152                 :      78092 :             op_name = json_string(op);
     153                 :      78092 :             ovsdb_operation_executor *executor = lookup_executor(op_name, &ro);
     154         [ +  - ]:      78092 :             if (executor) {
     155                 :      78092 :                 error = executor(&x, &parser, result);
     156                 :            :             } else {
     157                 :      78092 :                 ovsdb_parser_raise_error(&parser, "No operation \"%s\"",
     158                 :            :                                          op_name);
     159                 :            :             }
     160                 :            :         } else {
     161         [ #  # ]:          0 :             ovs_assert(ovsdb_parser_has_error(&parser));
     162                 :            :         }
     163                 :            : 
     164                 :            :         /* A parse error overrides any other error.
     165                 :            :          * An error overrides any other result. */
     166                 :      78092 :         parse_error = ovsdb_parser_finish(&parser);
     167         [ +  + ]:      78092 :         if (parse_error) {
     168                 :          1 :             ovsdb_error_destroy(error);
     169                 :          1 :             error = parse_error;
     170                 :            :         }
     171                 :            :         /* Create read-only violation error if there is one. */
     172 [ +  + ][ +  + ]:      78092 :         if (!error && read_only && !ro) {
                 [ +  + ]
     173                 :          2 :             error = ovsdb_error("not allowed",
     174                 :            :                                 "%s operation not allowed when "
     175                 :            :                                 "database server is in read only mode",
     176                 :            :                                 op_name);
     177                 :            :         }
     178         [ +  + ]:      78092 :         if (error) {
     179                 :         98 :             json_destroy(result);
     180                 :         98 :             result = ovsdb_error_to_json(error);
     181                 :            :         }
     182 [ +  + ][ +  + ]:      78092 :         if (error && !strcmp(ovsdb_error_get_tag(error), "not supported")
     183         [ +  - ]:          6 :             && timeout_msec) {
     184                 :          6 :             ovsdb_txn_abort(x.txn);
     185                 :          6 :             *timeout_msec = x.timeout_msec;
     186                 :            : 
     187                 :          6 :             json_destroy(result);
     188                 :          6 :             json_destroy(results);
     189                 :          6 :             results = NULL;
     190                 :          6 :             goto exit;
     191                 :            :         }
     192                 :            : 
     193                 :            :         /* Add result to array. */
     194                 :      78086 :         json_array_add(results, result);
     195         [ +  + ]:      78086 :         if (error) {
     196                 :         92 :             break;
     197                 :            :         }
     198                 :            :     }
     199                 :            : 
     200         [ +  + ]:      12577 :     if (!error) {
     201                 :      12485 :         error = ovsdb_txn_commit(x.txn, x.durable);
     202         [ +  + ]:      12485 :         if (error) {
     203                 :      12485 :             json_array_add(results, ovsdb_error_to_json(error));
     204                 :            :         }
     205                 :            :     } else {
     206                 :         92 :         ovsdb_txn_abort(x.txn);
     207                 :            :     }
     208                 :            : 
     209         [ +  + ]:      12586 :     while (json_array(results)->n < n_operations) {
     210                 :          9 :         json_array_add(results, json_null_create());
     211                 :            :     }
     212                 :            : 
     213                 :            : exit:
     214                 :      12583 :     ovsdb_error_destroy(error);
     215                 :      12583 :     ovsdb_symbol_table_destroy(x.symtab);
     216                 :            : 
     217                 :      12583 :     return results;
     218                 :            : }
     219                 :            : 
     220                 :            : static struct ovsdb_error *
     221                 :         14 : ovsdb_execute_commit(struct ovsdb_execution *x, struct ovsdb_parser *parser,
     222                 :            :                      struct json *result OVS_UNUSED)
     223                 :            : {
     224                 :            :     const struct json *durable;
     225                 :            : 
     226                 :         14 :     durable = ovsdb_parser_member(parser, "durable", OP_BOOLEAN);
     227 [ +  - ][ +  + ]:         14 :     if (durable && json_boolean(durable)) {
     228                 :          7 :         x->durable = true;
     229                 :            :     }
     230                 :         14 :     return NULL;
     231                 :            : }
     232                 :            : 
     233                 :            : static struct ovsdb_error *
     234                 :          0 : ovsdb_execute_abort(struct ovsdb_execution *x OVS_UNUSED,
     235                 :            :                     struct ovsdb_parser *parser OVS_UNUSED,
     236                 :            :                     struct json *result OVS_UNUSED)
     237                 :            : {
     238                 :          0 :     return ovsdb_error("aborted", "aborted by request");
     239                 :            : }
     240                 :            : 
     241                 :            : static struct ovsdb_table *
     242                 :      68451 : parse_table(struct ovsdb_execution *x,
     243                 :            :             struct ovsdb_parser *parser, const char *member)
     244                 :            : {
     245                 :            :     struct ovsdb_table *table;
     246                 :            :     const char *table_name;
     247                 :            :     const struct json *json;
     248                 :            : 
     249                 :      68451 :     json = ovsdb_parser_member(parser, member, OP_ID);
     250         [ -  + ]:      68451 :     if (!json) {
     251                 :          0 :         return NULL;
     252                 :            :     }
     253                 :      68451 :     table_name = json_string(json);
     254                 :            : 
     255                 :      68451 :     table = shash_find_data(&x->db->tables, table_name);
     256         [ -  + ]:      68451 :     if (!table) {
     257                 :          0 :         ovsdb_parser_raise_error(parser, "No table named %s.", table_name);
     258                 :            :     }
     259                 :      68451 :     return table;
     260                 :            : }
     261                 :            : 
     262                 :            : static OVS_WARN_UNUSED_RESULT struct ovsdb_error *
     263                 :      35784 : parse_row(const struct json *json, const struct ovsdb_table *table,
     264                 :            :           struct ovsdb_symbol_table *symtab,
     265                 :            :           struct ovsdb_row **rowp, struct ovsdb_column_set *columns)
     266                 :            : {
     267                 :            :     struct ovsdb_error *error;
     268                 :            :     struct ovsdb_row *row;
     269                 :            : 
     270                 :      35784 :     *rowp = NULL;
     271                 :            : 
     272         [ -  + ]:      35784 :     if (!table) {
     273                 :          0 :         return OVSDB_BUG("null table");
     274                 :            :     }
     275         [ -  + ]:      35784 :     if (!json) {
     276                 :          0 :         return OVSDB_BUG("null row");
     277                 :            :     }
     278                 :            : 
     279                 :      35784 :     row = ovsdb_row_create(table);
     280                 :      35784 :     error = ovsdb_row_from_json(row, json, symtab, columns);
     281         [ +  + ]:      35784 :     if (error) {
     282                 :         15 :         ovsdb_row_destroy(row);
     283                 :         15 :         return error;
     284                 :            :     } else {
     285                 :      35769 :         *rowp = row;
     286                 :      35769 :         return NULL;
     287                 :            :     }
     288                 :            : }
     289                 :            : 
     290                 :            : static struct ovsdb_error *
     291                 :      17228 : ovsdb_execute_insert(struct ovsdb_execution *x, struct ovsdb_parser *parser,
     292                 :            :                      struct json *result)
     293                 :            : {
     294                 :            :     struct ovsdb_table *table;
     295                 :      17228 :     struct ovsdb_row *row = NULL;
     296                 :            :     const struct json *uuid_name, *row_json;
     297                 :            :     struct ovsdb_error *error;
     298                 :            :     struct uuid row_uuid;
     299                 :            : 
     300                 :      17228 :     table = parse_table(x, parser, "table");
     301                 :      17228 :     uuid_name = ovsdb_parser_member(parser, "uuid-name", OP_ID | OP_OPTIONAL);
     302                 :      17228 :     row_json = ovsdb_parser_member(parser, "row", OP_OBJECT);
     303                 :      17228 :     error = ovsdb_parser_get_error(parser);
     304         [ +  + ]:      17228 :     if (error) {
     305                 :          1 :         return error;
     306                 :            :     }
     307                 :            : 
     308         [ +  + ]:      17227 :     if (uuid_name) {
     309                 :            :         struct ovsdb_symbol *symbol;
     310                 :            : 
     311                 :      16528 :         symbol = ovsdb_symbol_table_insert(x->symtab, json_string(uuid_name));
     312         [ +  + ]:      16528 :         if (symbol->created) {
     313                 :          1 :             return ovsdb_syntax_error(uuid_name, "duplicate uuid-name",
     314                 :            :                                       "This \"uuid-name\" appeared on an "
     315                 :            :                                       "earlier \"insert\" operation.");
     316                 :            :         }
     317                 :      16527 :         row_uuid = symbol->uuid;
     318                 :      16527 :         symbol->created = true;
     319                 :            :     } else {
     320                 :        699 :         uuid_generate(&row_uuid);
     321                 :            :     }
     322                 :            : 
     323         [ +  - ]:      17226 :     if (!error) {
     324                 :      17226 :         error = parse_row(row_json, table, x->symtab, &row, NULL);
     325                 :            :     }
     326         [ +  + ]:      17226 :     if (!error) {
     327                 :            :         /* Check constraints for columns not included in "row", in case the
     328                 :            :          * default values do not satisfy the constraints.  We could check only
     329                 :            :          * the columns that have their default values by supplying an
     330                 :            :          * ovsdb_column_set to parse_row() above, but I suspect that this is
     331                 :            :          * cheaper.  */
     332                 :            :         const struct shash_node *node;
     333                 :            : 
     334 [ +  + ][ -  + ]:     333878 :         SHASH_FOR_EACH (node, &table->schema->columns) {
     335                 :     316667 :             const struct ovsdb_column *column = node->data;
     336                 :     316667 :             const struct ovsdb_datum *datum = &row->fields[column->index];
     337                 :            : 
     338                 :            :             /* If there are 0 keys or pairs, there's nothing to check.
     339                 :            :              * If there is 1, it might be a default value.
     340                 :            :              * If there are more, it can't be a default value, so the value has
     341                 :            :              * already been checked. */
     342         [ +  + ]:     316667 :             if (datum->n == 1) {
     343                 :     123717 :                 error = ovsdb_datum_check_constraints(datum, &column->type);
     344         [ +  + ]:     123717 :                 if (error) {
     345                 :          7 :                     ovsdb_row_destroy(row);
     346                 :          7 :                     break;
     347                 :            :                 }
     348                 :            :             }
     349                 :            :         }
     350                 :            :     }
     351         [ +  + ]:      17226 :     if (!error) {
     352                 :      17211 :         *ovsdb_row_get_uuid_rw(row) = row_uuid;
     353                 :      17211 :         ovsdb_txn_row_insert(x->txn, row);
     354                 :      17211 :         json_object_put(result, "uuid",
     355                 :      17211 :                         ovsdb_datum_to_json(&row->fields[OVSDB_COL_UUID],
     356                 :            :                                             &ovsdb_type_uuid));
     357                 :            :     }
     358                 :      17228 :     return error;
     359                 :            : }
     360                 :            : 
     361                 :            : static struct ovsdb_error *
     362                 :       2487 : ovsdb_execute_select(struct ovsdb_execution *x, struct ovsdb_parser *parser,
     363                 :            :                      struct json *result)
     364                 :            : {
     365                 :            :     struct ovsdb_table *table;
     366                 :            :     const struct json *where, *columns_json, *sort_json;
     367                 :       2487 :     struct ovsdb_condition condition = OVSDB_CONDITION_INITIALIZER(&condition);
     368                 :       2487 :     struct ovsdb_column_set columns = OVSDB_COLUMN_SET_INITIALIZER;
     369                 :       2487 :     struct ovsdb_column_set sort = OVSDB_COLUMN_SET_INITIALIZER;
     370                 :            :     struct ovsdb_error *error;
     371                 :            : 
     372                 :       2487 :     table = parse_table(x, parser, "table");
     373                 :       2487 :     where = ovsdb_parser_member(parser, "where", OP_ARRAY);
     374                 :       2487 :     columns_json = ovsdb_parser_member(parser, "columns",
     375                 :            :                                        OP_ARRAY | OP_OPTIONAL);
     376                 :       2487 :     sort_json = ovsdb_parser_member(parser, "sort", OP_ARRAY | OP_OPTIONAL);
     377                 :            : 
     378                 :       2487 :     error = ovsdb_parser_get_error(parser);
     379         [ +  - ]:       2487 :     if (!error) {
     380                 :       2487 :         error = ovsdb_condition_from_json(table->schema, where, x->symtab,
     381                 :            :                                           &condition);
     382                 :            :     }
     383         [ +  - ]:       2487 :     if (!error) {
     384                 :       2487 :         error = ovsdb_column_set_from_json(columns_json, table->schema,
     385                 :            :                                            &columns);
     386                 :            :     }
     387         [ +  - ]:       2487 :     if (!error) {
     388                 :       2487 :         error = ovsdb_column_set_from_json(sort_json, table->schema, &sort);
     389                 :            :     }
     390         [ +  - ]:       2487 :     if (!error) {
     391                 :       2487 :         struct ovsdb_row_set rows = OVSDB_ROW_SET_INITIALIZER;
     392                 :            : 
     393                 :       2487 :         ovsdb_query_distinct(table, &condition, &columns, &rows);
     394                 :       2487 :         ovsdb_row_set_sort(&rows, &sort);
     395                 :       2487 :         json_object_put(result, "rows",
     396                 :            :                         ovsdb_row_set_to_json(&rows, &columns));
     397                 :            : 
     398                 :       2487 :         ovsdb_row_set_destroy(&rows);
     399                 :            :     }
     400                 :            : 
     401                 :       2487 :     ovsdb_column_set_destroy(&columns);
     402                 :       2487 :     ovsdb_column_set_destroy(&sort);
     403                 :       2487 :     ovsdb_condition_destroy(&condition);
     404                 :            : 
     405                 :       2487 :     return error;
     406                 :            : }
     407                 :            : 
     408                 :            : struct update_row_cbdata {
     409                 :            :     size_t n_matches;
     410                 :            :     struct ovsdb_txn *txn;
     411                 :            :     const struct ovsdb_row *row;
     412                 :            :     const struct ovsdb_column_set *columns;
     413                 :            : };
     414                 :            : 
     415                 :            : static bool
     416                 :      18636 : update_row_cb(const struct ovsdb_row *row, void *ur_)
     417                 :            : {
     418                 :      18636 :     struct update_row_cbdata *ur = ur_;
     419                 :            : 
     420                 :      18636 :     ur->n_matches++;
     421         [ +  + ]:      18636 :     if (!ovsdb_row_equal_columns(row, ur->row, ur->columns)) {
     422                 :      16240 :         ovsdb_row_update_columns(ovsdb_txn_row_modify(ur->txn, row),
     423                 :            :                                  ur->row, ur->columns);
     424                 :            :     }
     425                 :            : 
     426                 :      18636 :     return true;
     427                 :            : }
     428                 :            : 
     429                 :            : static struct ovsdb_error *
     430                 :      18558 : ovsdb_execute_update(struct ovsdb_execution *x, struct ovsdb_parser *parser,
     431                 :            :                      struct json *result)
     432                 :            : {
     433                 :            :     struct ovsdb_table *table;
     434                 :            :     const struct json *where, *row_json;
     435                 :      18558 :     struct ovsdb_condition condition = OVSDB_CONDITION_INITIALIZER(&condition);
     436                 :      18558 :     struct ovsdb_column_set columns = OVSDB_COLUMN_SET_INITIALIZER;
     437                 :      18558 :     struct ovsdb_row *row = NULL;
     438                 :            :     struct update_row_cbdata ur;
     439                 :            :     struct ovsdb_error *error;
     440                 :            : 
     441                 :      18558 :     table = parse_table(x, parser, "table");
     442                 :      18558 :     where = ovsdb_parser_member(parser, "where", OP_ARRAY);
     443                 :      18558 :     row_json = ovsdb_parser_member(parser, "row", OP_OBJECT);
     444                 :      18558 :     error = ovsdb_parser_get_error(parser);
     445         [ +  - ]:      18558 :     if (!error) {
     446                 :      18558 :         error = parse_row(row_json, table, x->symtab, &row, &columns);
     447                 :            :     }
     448         [ +  + ]:      18558 :     if (!error) {
     449                 :            :         size_t i;
     450                 :            : 
     451         [ +  + ]:      69467 :         for (i = 0; i < columns.n_columns; i++) {
     452                 :      50930 :             const struct ovsdb_column *column = columns.columns[i];
     453                 :            : 
     454         [ +  + ]:      50930 :             if (!column->mutable) {
     455                 :         14 :                 error = ovsdb_syntax_error(parser->json,
     456                 :            :                                            "constraint violation",
     457                 :            :                                            "Cannot update immutable column %s "
     458                 :            :                                            "in table %s.",
     459                 :         14 :                                            column->name, table->schema->name);
     460                 :         14 :                 break;
     461                 :            :             }
     462                 :            :         }
     463                 :            :     }
     464         [ +  + ]:      18558 :     if (!error) {
     465                 :      18537 :         error = ovsdb_condition_from_json(table->schema, where, x->symtab,
     466                 :            :                                           &condition);
     467                 :            :     }
     468         [ +  + ]:      18558 :     if (!error) {
     469                 :      18537 :         ur.n_matches = 0;
     470                 :      18537 :         ur.txn = x->txn;
     471                 :      18537 :         ur.row = row;
     472                 :      18537 :         ur.columns = &columns;
     473                 :      18537 :         ovsdb_query(table, &condition, update_row_cb, &ur);
     474                 :      18537 :         json_object_put(result, "count", json_integer_create(ur.n_matches));
     475                 :            :     }
     476                 :            : 
     477                 :      18558 :     ovsdb_row_destroy(row);
     478                 :      18558 :     ovsdb_column_set_destroy(&columns);
     479                 :      18558 :     ovsdb_condition_destroy(&condition);
     480                 :            : 
     481                 :      18558 :     return error;
     482                 :            : }
     483                 :            : 
     484                 :            : struct mutate_row_cbdata {
     485                 :            :     size_t n_matches;
     486                 :            :     struct ovsdb_txn *txn;
     487                 :            :     const struct ovsdb_mutation_set *mutations;
     488                 :            :     struct ovsdb_error **error;
     489                 :            : };
     490                 :            : 
     491                 :            : static bool
     492                 :       2226 : mutate_row_cb(const struct ovsdb_row *row, void *mr_)
     493                 :            : {
     494                 :       2226 :     struct mutate_row_cbdata *mr = mr_;
     495                 :            : 
     496                 :       2226 :     mr->n_matches++;
     497                 :       2226 :     *mr->error = ovsdb_mutation_set_execute(ovsdb_txn_row_modify(mr->txn, row),
     498                 :            :                                             mr->mutations);
     499                 :       2226 :     return *mr->error == NULL;
     500                 :            : }
     501                 :            : 
     502                 :            : static struct ovsdb_error *
     503                 :       2233 : ovsdb_execute_mutate(struct ovsdb_execution *x, struct ovsdb_parser *parser,
     504                 :            :                      struct json *result)
     505                 :            : {
     506                 :            :     struct ovsdb_table *table;
     507                 :            :     const struct json *where;
     508                 :            :     const struct json *mutations_json;
     509                 :       2233 :     struct ovsdb_condition condition = OVSDB_CONDITION_INITIALIZER(&condition);
     510                 :       2233 :     struct ovsdb_mutation_set mutations = OVSDB_MUTATION_SET_INITIALIZER;
     511                 :       2233 :     struct ovsdb_row *row = NULL;
     512                 :            :     struct mutate_row_cbdata mr;
     513                 :            :     struct ovsdb_error *error;
     514                 :            : 
     515                 :       2233 :     table = parse_table(x, parser, "table");
     516                 :       2233 :     where = ovsdb_parser_member(parser, "where", OP_ARRAY);
     517                 :       2233 :     mutations_json = ovsdb_parser_member(parser, "mutations", OP_ARRAY);
     518                 :       2233 :     error = ovsdb_parser_get_error(parser);
     519         [ +  - ]:       2233 :     if (!error) {
     520                 :       2233 :         error = ovsdb_mutation_set_from_json(table->schema, mutations_json,
     521                 :            :                                              x->symtab, &mutations);
     522                 :            :     }
     523         [ +  + ]:       2233 :     if (!error) {
     524                 :       2219 :         error = ovsdb_condition_from_json(table->schema, where, x->symtab,
     525                 :            :                                           &condition);
     526                 :            :     }
     527         [ +  + ]:       2233 :     if (!error) {
     528                 :       2219 :         mr.n_matches = 0;
     529                 :       2219 :         mr.txn = x->txn;
     530                 :       2219 :         mr.mutations = &mutations;
     531                 :       2219 :         mr.error = &error;
     532                 :       2219 :         ovsdb_query(table, &condition, mutate_row_cb, &mr);
     533                 :       2219 :         json_object_put(result, "count", json_integer_create(mr.n_matches));
     534                 :            :     }
     535                 :            : 
     536                 :       2233 :     ovsdb_row_destroy(row);
     537                 :       2233 :     ovsdb_mutation_set_destroy(&mutations);
     538                 :       2233 :     ovsdb_condition_destroy(&condition);
     539                 :            : 
     540                 :       2233 :     return error;
     541                 :            : }
     542                 :            : 
     543                 :            : struct delete_row_cbdata {
     544                 :            :     size_t n_matches;
     545                 :            :     const struct ovsdb_table *table;
     546                 :            :     struct ovsdb_txn *txn;
     547                 :            : };
     548                 :            : 
     549                 :            : static bool
     550                 :        862 : delete_row_cb(const struct ovsdb_row *row, void *dr_)
     551                 :            : {
     552                 :        862 :     struct delete_row_cbdata *dr = dr_;
     553                 :            : 
     554                 :        862 :     dr->n_matches++;
     555                 :        862 :     ovsdb_txn_row_delete(dr->txn, row);
     556                 :            : 
     557                 :        862 :     return true;
     558                 :            : }
     559                 :            : 
     560                 :            : static struct ovsdb_error *
     561                 :        824 : ovsdb_execute_delete(struct ovsdb_execution *x, struct ovsdb_parser *parser,
     562                 :            :                      struct json *result)
     563                 :            : {
     564                 :            :     struct ovsdb_table *table;
     565                 :            :     const struct json *where;
     566                 :        824 :     struct ovsdb_condition condition = OVSDB_CONDITION_INITIALIZER(&condition);
     567                 :            :     struct ovsdb_error *error;
     568                 :            : 
     569                 :        824 :     where = ovsdb_parser_member(parser, "where", OP_ARRAY);
     570                 :        824 :     table = parse_table(x, parser, "table");
     571                 :        824 :     error = ovsdb_parser_get_error(parser);
     572         [ +  - ]:        824 :     if (!error) {
     573                 :        824 :         error = ovsdb_condition_from_json(table->schema, where, x->symtab,
     574                 :            :                                           &condition);
     575                 :            :     }
     576         [ +  - ]:        824 :     if (!error) {
     577                 :            :         struct delete_row_cbdata dr;
     578                 :            : 
     579                 :        824 :         dr.n_matches = 0;
     580                 :        824 :         dr.table = table;
     581                 :        824 :         dr.txn = x->txn;
     582                 :        824 :         ovsdb_query(table, &condition, delete_row_cb, &dr);
     583                 :            : 
     584                 :        824 :         json_object_put(result, "count", json_integer_create(dr.n_matches));
     585                 :            :     }
     586                 :            : 
     587                 :        824 :     ovsdb_condition_destroy(&condition);
     588                 :            : 
     589                 :        824 :     return error;
     590                 :            : }
     591                 :            : 
     592                 :            : struct wait_auxdata {
     593                 :            :     struct ovsdb_row_hash *actual;
     594                 :            :     struct ovsdb_row_hash *expected;
     595                 :            :     bool *equal;
     596                 :            : };
     597                 :            : 
     598                 :            : static bool
     599                 :      27164 : ovsdb_execute_wait_query_cb(const struct ovsdb_row *row, void *aux_)
     600                 :            : {
     601                 :      27164 :     struct wait_auxdata *aux = aux_;
     602                 :            : 
     603         [ +  + ]:      27164 :     if (ovsdb_row_hash_contains(aux->expected, row)) {
     604                 :      27139 :         ovsdb_row_hash_insert(aux->actual, row);
     605                 :      27139 :         return true;
     606                 :            :     } else {
     607                 :            :         /* The query row isn't in the expected result set, so the actual and
     608                 :            :          * expected results sets definitely differ and we can short-circuit the
     609                 :            :          * rest of the query. */
     610                 :         25 :         *aux->equal = false;
     611                 :         25 :         return false;
     612                 :            :     }
     613                 :            : }
     614                 :            : 
     615                 :            : static struct ovsdb_error *
     616                 :      27121 : ovsdb_execute_wait(struct ovsdb_execution *x, struct ovsdb_parser *parser,
     617                 :            :                    struct json *result OVS_UNUSED)
     618                 :            : {
     619                 :            :     struct ovsdb_table *table;
     620                 :            :     const struct json *timeout, *where, *columns_json, *until, *rows;
     621                 :      27121 :     struct ovsdb_condition condition = OVSDB_CONDITION_INITIALIZER(&condition);
     622                 :      27121 :     struct ovsdb_column_set columns = OVSDB_COLUMN_SET_INITIALIZER;
     623                 :      27121 :     struct ovsdb_row_hash expected = OVSDB_ROW_HASH_INITIALIZER(expected);
     624                 :      27121 :     struct ovsdb_row_hash actual = OVSDB_ROW_HASH_INITIALIZER(actual);
     625                 :            :     struct ovsdb_error *error;
     626                 :            :     struct wait_auxdata aux;
     627                 :      27121 :     long long int timeout_msec = 0;
     628                 :            :     size_t i;
     629                 :            : 
     630                 :      27121 :     timeout = ovsdb_parser_member(parser, "timeout", OP_NUMBER | OP_OPTIONAL);
     631                 :      27121 :     where = ovsdb_parser_member(parser, "where", OP_ARRAY);
     632                 :      27121 :     columns_json = ovsdb_parser_member(parser, "columns",
     633                 :            :                                        OP_ARRAY | OP_OPTIONAL);
     634                 :      27121 :     until = ovsdb_parser_member(parser, "until", OP_STRING);
     635                 :      27121 :     rows = ovsdb_parser_member(parser, "rows", OP_ARRAY);
     636                 :      27121 :     table = parse_table(x, parser, "table");
     637                 :      27121 :     error = ovsdb_parser_get_error(parser);
     638         [ +  - ]:      27121 :     if (!error) {
     639                 :      27121 :         error = ovsdb_condition_from_json(table->schema, where, x->symtab,
     640                 :            :                                           &condition);
     641                 :            :     }
     642         [ +  - ]:      27121 :     if (!error) {
     643                 :      27121 :         error = ovsdb_column_set_from_json(columns_json, table->schema,
     644                 :            :                                            &columns);
     645                 :            :     }
     646         [ +  - ]:      27121 :     if (!error) {
     647         [ +  - ]:      27121 :         if (timeout) {
     648         [ -  + ]:      27121 :             timeout_msec = MIN(LLONG_MAX, json_real(timeout));
     649         [ -  + ]:      27121 :             if (timeout_msec < 0) {
     650                 :          0 :                 error = ovsdb_syntax_error(timeout, NULL,
     651                 :            :                                            "timeout must be nonnegative");
     652         [ +  + ]:      27121 :             } else if (timeout_msec < x->timeout_msec) {
     653                 :      27121 :                 x->timeout_msec = timeout_msec;
     654                 :            :             }
     655                 :            :         } else {
     656                 :          0 :             timeout_msec = LLONG_MAX;
     657                 :            :         }
     658                 :            :     }
     659         [ +  - ]:      27121 :     if (!error) {
     660         [ +  + ]:      27121 :         if (strcmp(json_string(until), "==")
     661         [ -  + ]:         21 :             && strcmp(json_string(until), "!=")) {
     662                 :          0 :             error = ovsdb_syntax_error(until, NULL,
     663                 :            :                                        "\"until\" must be \"==\" or \"!=\"");
     664                 :            :         }
     665                 :            :     }
     666         [ +  - ]:      27121 :     if (!error) {
     667                 :            :         /* Parse "rows" into 'expected'. */
     668                 :      27121 :         ovsdb_row_hash_init(&expected, &columns);
     669         [ +  + ]:      54301 :         for (i = 0; i < rows->u.array.n; i++) {
     670                 :            :             struct ovsdb_row *row;
     671                 :            : 
     672                 :      27180 :             row = ovsdb_row_create(table);
     673                 :      27180 :             error = ovsdb_row_from_json(row, rows->u.array.elems[i], x->symtab,
     674                 :            :                                         NULL);
     675         [ -  + ]:      27180 :             if (error) {
     676                 :          0 :                 ovsdb_row_destroy(row);
     677                 :          0 :                 break;
     678                 :            :             }
     679                 :            : 
     680         [ -  + ]:      27180 :             if (!ovsdb_row_hash_insert(&expected, row)) {
     681                 :            :                 /* XXX Perhaps we should abort with an error or log a
     682                 :            :                  * warning. */
     683                 :          0 :                 ovsdb_row_destroy(row);
     684                 :            :             }
     685                 :            :         }
     686                 :            :     }
     687         [ +  - ]:      27121 :     if (!error) {
     688                 :            :         /* Execute query. */
     689                 :      27121 :         bool equal = true;
     690                 :      27121 :         ovsdb_row_hash_init(&actual, &columns);
     691                 :      27121 :         aux.actual = &actual;
     692                 :      27121 :         aux.expected = &expected;
     693                 :      27121 :         aux.equal = &equal;
     694                 :      27121 :         ovsdb_query(table, &condition, ovsdb_execute_wait_query_cb, &aux);
     695         [ +  + ]:      27121 :         if (equal) {
     696                 :            :             /* We know that every row in 'actual' is also in 'expected'.  We
     697                 :            :              * also know that all of the rows in 'actual' are distinct and that
     698                 :            :              * all of the rows in 'expected' are distinct.  Therefore, if
     699                 :            :              * 'actual' and 'expected' have the same number of rows, then they
     700                 :            :              * have the same content. */
     701                 :      27096 :             size_t n_actual = ovsdb_row_hash_count(&actual);
     702                 :      27096 :             size_t n_expected = ovsdb_row_hash_count(&expected);
     703                 :      27096 :             equal = n_actual == n_expected;
     704                 :            :         }
     705         [ +  + ]:      27121 :         if (!strcmp(json_string(until), "==") != equal) {
     706 [ +  - ][ +  + ]:         37 :             if (timeout && x->elapsed_msec >= timeout_msec) {
     707         [ +  + ]:         62 :                 if (x->elapsed_msec) {
     708                 :          1 :                     error = ovsdb_error("timed out",
     709                 :            :                                         "\"wait\" timed out after %lld ms",
     710                 :            :                                         x->elapsed_msec);
     711                 :            :                 } else {
     712                 :         30 :                     error = ovsdb_error("timed out",
     713                 :            :                                         "\"where\" clause test failed");
     714                 :            :                 }
     715                 :            :             } else {
     716                 :            :                 /* ovsdb_execute() will change this, if triggers really are
     717                 :            :                  * supported. */
     718                 :      27121 :                 error = ovsdb_error("not supported", "triggers not supported");
     719                 :            :             }
     720                 :            :         }
     721                 :            :     }
     722                 :            : 
     723                 :            : 
     724                 :      27121 :     ovsdb_row_hash_destroy(&expected, true);
     725                 :      27121 :     ovsdb_row_hash_destroy(&actual, false);
     726                 :      27121 :     ovsdb_column_set_destroy(&columns);
     727                 :      27121 :     ovsdb_condition_destroy(&condition);
     728                 :            : 
     729                 :      27121 :     return error;
     730                 :            : }
     731                 :            : 
     732                 :            : static struct ovsdb_error *
     733                 :       4131 : ovsdb_execute_comment(struct ovsdb_execution *x, struct ovsdb_parser *parser,
     734                 :            :                       struct json *result OVS_UNUSED)
     735                 :            : {
     736                 :            :     const struct json *comment;
     737                 :            : 
     738                 :       4131 :     comment = ovsdb_parser_member(parser, "comment", OP_STRING);
     739         [ -  + ]:       4131 :     if (!comment) {
     740                 :          0 :         return NULL;
     741                 :            :     }
     742                 :       4131 :     ovsdb_txn_add_comment(x->txn, json_string(comment));
     743                 :            : 
     744                 :       4131 :     return NULL;
     745                 :            : }
     746                 :            : 
     747                 :            : static struct ovsdb_error *
     748                 :       5496 : ovsdb_execute_assert(struct ovsdb_execution *x, struct ovsdb_parser *parser,
     749                 :            :                      struct json *result OVS_UNUSED)
     750                 :            : {
     751                 :            :     const struct json *lock_name;
     752                 :            : 
     753                 :       5496 :     lock_name = ovsdb_parser_member(parser, "lock", OP_ID);
     754         [ -  + ]:       5496 :     if (!lock_name) {
     755                 :          0 :         return NULL;
     756                 :            :     }
     757                 :            : 
     758         [ +  - ]:       5496 :     if (x->session) {
     759                 :            :         const struct ovsdb_lock_waiter *waiter;
     760                 :            : 
     761                 :       5496 :         waiter = ovsdb_session_get_lock_waiter(x->session,
     762                 :            :                                                json_string(lock_name));
     763 [ +  - ][ +  - ]:       5496 :         if (waiter && ovsdb_lock_waiter_is_owner(waiter)) {
     764                 :       5496 :             return NULL;
     765                 :            :         }
     766                 :            :     }
     767                 :            : 
     768                 :          0 :     return ovsdb_error("not owner", "Asserted lock %s not held.",
     769                 :            :                        json_string(lock_name));
     770                 :            : }

Generated by: LCOV version 1.12