diff mbox

[ovs-dev,4/4,v4] ovsdb-idl: Autogenerated functions for compound indexes

Message ID AT5PR84MB02107D99876CF76B1EC43E2EDC680@AT5PR84MB0210.NAMPRD84.PROD.OUTLOOK.COM
State Not Applicable
Headers show

Commit Message

Rodriguez Betancourt, Esteban Dec. 28, 2016, 7:41 p.m. UTC
Generates and fill the default comparators for columns with
type int, real, string. Also creates the macros that allow
to iterate over the contents of the index, and perform
queries.

Signed-off-by: Arnoldo Lutz Guevara <arnoldo.lutz.guevara@hpe.com>
Signed-off-by: Esteban Rodriguez Betancourt <estebarb@hpe.com>
Co-authored-by: Arnoldo Lutz Guevara <arnoldo.lutz.guevara@hpe.com>
Co-authored-by: Esteban Rodriguez Betancourt <estebarb@hpe.com>
---
 ovsdb/ovsdb-idlc.in | 259 +++++++++++++++++++++++++++++++++++++++++++++++++++
 tests/ovsdb-idl.at  | 263 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 tests/test-ovsdb.c  | 240 ++++++++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 761 insertions(+), 1 deletion(-)
diff mbox

Patch

diff --git a/ovsdb/ovsdb-idlc.in b/ovsdb/ovsdb-idlc.in
index 721ab50..a1ff3e6 100755
--- a/ovsdb/ovsdb-idlc.in
+++ b/ovsdb/ovsdb-idlc.in
@@ -8,6 +8,7 @@  import sys
 import ovs.json
 import ovs.db.error
 import ovs.db.schema
+from ovs.db.types import StringType, IntegerType, RealType
 
 argv0 = sys.argv[0]
 
@@ -201,6 +202,26 @@  static inline bool %(s)s_is_deleted(const struct %(s)s *row)
     return %(s)s_row_get_seqno(row, OVSDB_IDL_CHANGE_DELETE) > 0;
 }
 
+void %(s)s_index_destroy_row(const struct %(s)s *);
+int %(s)s_index_compare(struct ovsdb_idl_index_cursor *, const struct %(s)s *, const struct %(s)s *);
+const struct %(s)s *%(s)s_index_first(struct ovsdb_idl_index_cursor *);
+const struct %(s)s *%(s)s_index_next(struct ovsdb_idl_index_cursor *);
+const struct %(s)s *%(s)s_index_find(struct ovsdb_idl_index_cursor *, const struct %(s)s *);
+const struct %(s)s *%(s)s_index_forward_to(struct ovsdb_idl_index_cursor *, const struct %(s)s *);
+const struct %(s)s *%(s)s_index_get_data(const struct ovsdb_idl_index_cursor *);
+#define %(S)s_FOR_EACH_RANGE(ROW, CURSOR, FROM, TO) \\
+        for ((ROW) = %(s)s_index_forward_to(CURSOR, FROM); \\
+             ((ROW) && %(s)s_index_compare(CURSOR, ROW, TO) <= 0); \\
+             (ROW) = %(s)s_index_next(CURSOR))
+#define %(S)s_FOR_EACH_EQUAL(ROW, CURSOR, KEY) \\
+        for ((ROW) = %(s)s_index_find(CURSOR, KEY); \\
+             ((ROW) && %(s)s_index_compare(CURSOR, ROW, KEY) == 0); \\
+             (ROW) = %(s)s_index_next(CURSOR))
+#define %(S)s_FOR_EACH_BYINDEX(ROW, CURSOR) \\
+        for ((ROW) = %(s)s_index_first(CURSOR); \\
+             (ROW); \\
+             (ROW) = %(s)s_index_next(CURSOR))
+
 void %(s)s_init(struct %(s)s *);
 void %(s)s_delete(const struct %(s)s *);
 struct %(s)s *%(s)s_insert(struct ovsdb_idl_txn *);
@@ -257,6 +278,19 @@  bool %(s)s_is_updated(const struct %(s)s *, enum %(s)s_column_id);
         print
 
     # Table indexes.
+        print "struct %(s)s * %(s)s_index_init_row(struct ovsdb_idl*, const struct ovsdb_idl_table_class *);" % {'s': structName}
+        print
+        for columnName, column in sorted(table.columns.iteritems()):
+            print 'void %(s)s_index_set_%(c)s(const struct %(s)s *,' % {'s': structName, 'c': columnName},
+            if column.type.is_smap():
+                args = ['const struct smap *']
+            else:
+                comment, members = cMembers(prefix, tableName, columnName,
+                                            column, True)
+                args = ['%(type)s%(name)s' % member for member in members]
+            print '%s);' % ', '.join(args)
+
+        print
     printEnum("%stable_id" % prefix.lower(), ["%sTABLE_%s" % (prefix.upper(), tableName.upper()) for tableName in sorted(schema.tables)] + ["%sN_TABLES" % prefix.upper()])
     print
     for tableName in schema.tables:
@@ -979,6 +1013,231 @@  void
                 print "    free(%s);" % var
             print "}"
 
+# Index table related functions
+        print '''
+/* Destroy 'row' of kind "%(t)s". The row must have been
+ * created with ovsdb_idl_index_init_row.
+ */
+void
+%(s)s_index_destroy_row(const struct %(s)s *row)
+{
+    ovsdb_idl_index_destroy_row__(&row->header_);
+}
+        ''' % { 's' : structName, 't': tableName }
+        print """
+/* Creates a new row of kind "%(t)s". */
+struct %(s)s *
+%(s)s_index_init_row(struct ovsdb_idl* idl, const struct ovsdb_idl_table_class *class)
+{""" % {'s': structName, 't': tableName}
+        #for columnName, column in sorted(table.columns.iteritems()):
+        #    if column.type.is_smap():
+        #        print "    smap_init(&row->%s);" % columnName
+        print "    return (struct %(s)s *) ovsdb_idl_index_init_row(idl, class);" % {'s': structName, 't': tableName}
+        print "}"
+
+        print '''
+/*  This function is used to compare "%(s)s" records on table in iteration loops for compound-index operations.
+    After been called, cursor point to current position in the index
+    Parameters: struct ovsdb_idl_index_cursor *cursor. Cursor used to iterate over the indexed data on this table.
+                const struct "%(s)s" *const_data1,  const struct "%(s)s" *const_data2. Data to be compared.
+    Return value: 0 if both data values are equal, -1 if first parameter is less than second and 1 otherwise. */''' % {'s' : structName}
+        print 'int'
+        print '''%(s)s_index_compare(struct ovsdb_idl_index_cursor *cursor, const struct %(s)s *const_data1,  const struct %(s)s *const_data2)
+{
+    struct %(s)s *data1 = CONST_CAST(struct %(s)s *, const_data1);
+    struct %(s)s *data2 = CONST_CAST(struct %(s)s *, const_data2);
+    return ovsdb_idl_index_compare(cursor, &data1->header_, &data2->header_);
+}''' % { 's' : structName }
+        print '''
+/*  This function is called to position the cursor at the first row in "%(s)s" table on the associated compound-index. 
+    Parameters: struct ovsdb_idl_index_cursor *cursor. Cursor used to iterate over the indexed data on this table.
+    Return value: The first row in the corresponding index. */''' %  {'s' : structName }
+        print '''const struct %(s)s *\n%(s)s_index_first(struct ovsdb_idl_index_cursor *cursor)
+{
+    return %(s)s_cast(ovsdb_idl_index_first(cursor));
+}''' % { 's' : structName }
+        print '''
+/*  This function is called to position the cursor at the next row in "%(s)s" table on the associated compound-index. 
+    Parameters: struct ovsdb_idl_index_cursor *cursor. Cursor used to iterate over the indexed data on this table.
+    Return value: The next row in the corresponding index. */''' %  {'s' : structName, 'c' : columnName }
+        print '''const struct %(s)s *\n%(s)s_index_next(struct ovsdb_idl_index_cursor *cursor)
+{
+    return %(s)s_cast(ovsdb_idl_index_next(cursor));
+}''' % { 's' : structName }
+        print '''
+/*  This function is used to find the data of the row in "%(s)s" table that meet criteria with the requested data
+    associated in the compound-index. 
+    Parameters: struct ovsdb_idl_index_cursor *cursor. Cursor used to iterate over the indexed data on this table.
+                const struct %(s)s *const_data. Data to be searched.
+    Return value: The row in the corresponding index if found or NULL otherwise. */''' %  {'s' : structName }
+        print '''const struct %(s)s *\n%(s)s_index_find(struct ovsdb_idl_index_cursor *cursor, const struct %(s)s *const_data)
+{
+    struct %(s)s *data = CONST_CAST(struct %(s)s *, const_data);
+    return %(s)s_cast(ovsdb_idl_index_find(cursor, &data->header_));
+}''' % { 's' : structName }
+        print '''
+/*  This function is used to set the cursor pointing to the row in "%(s)s" table that meet criteria of the requested data
+    associated in the compound-index. 
+    Parameters: struct ovsdb_idl_index_cursor *cursor. Cursor used to iterate over the indexed data on this table.
+                const struct %(s)s *const_data. Data to be searched.
+    Return value: The row in the corresponding index closest to the criteria. */''' %  {'s' : structName }
+        print '''const struct %(s)s *\n%(s)s_index_forward_to(struct ovsdb_idl_index_cursor *cursor, const struct %(s)s *const_data)
+{
+    struct %(s)s *data = CONST_CAST(struct %(s)s *, const_data);
+    return %(s)s_cast(ovsdb_idl_index_forward_to(cursor, &data->header_));
+}''' % { 's' : structName }
+        print '''
+/*  This function is used to get the data of the row in the current position pointed by the cursor in
+    "%(s)s" table.
+    Parameters: struct ovsdb_idl_index_cursor *cursor. Cursor used to iterate over the indexed data on this table.
+    Return value: The row in the corresponding index if found or NULL otherwise. */''' %  {'s' : structName, 'c' : columnName }
+        print '''const struct %(s)s *\n%(s)s_index_get_data(const struct ovsdb_idl_index_cursor *cursor)
+{
+    return %(s)s_cast(ovsdb_idl_index_data(CONST_CAST(struct ovsdb_idl_index_cursor*, cursor)));
+}''' % { 's' : structName }
+        # Indexes Set functions
+        for columnName, column in sorted(table.columns.iteritems()):
+            type = column.type
+
+            comment, members = cMembers(prefix, tableName, columnName,
+                                        column, True)
+
+            if type.is_smap():
+                print comment
+                print "//TODO: WRITE A REAL COMMENT!"
+                print """void
+%(s)s_index_set_%(c)s(const struct %(s)s *row, const struct smap *%(c)s)
+{
+    struct ovsdb_datum *datum = xmalloc(sizeof(struct ovsdb_datum));
+
+    if (%(c)s) {
+        struct smap_node *node;
+        size_t i;
+
+        datum->n = smap_count(%(c)s);
+        datum->keys = xmalloc(datum->n * sizeof *datum->keys);
+        datum->values = xmalloc(datum->n * sizeof *datum->values);
+
+        i = 0;
+        SMAP_FOR_EACH (node, %(c)s) {
+            datum->keys[i].string = xstrdup(node->key);
+            datum->values[i].string = xstrdup(node->value);
+            i++;
+        }
+        ovsdb_datum_sort_unique(datum, OVSDB_TYPE_STRING, OVSDB_TYPE_STRING);
+    } else {
+        ovsdb_datum_init_empty(datum);
+    }
+    ovsdb_idl_index_write_(CONST_CAST(struct ovsdb_idl_row *, &row->header_),
+                           &%(s)s_columns[%(S)s_COL_%(C)s],
+                           datum,
+                           &%(p)stable_classes[%(P)sTABLE_%(T)s]);
+}
+""" % {'t': tableName,
+       'p': prefix,
+       'P': prefix.upper(),
+       's': structName,
+       'S': structName.upper(),
+       'c': columnName,
+       'C': columnName.upper(),
+       't': tableName,
+       'T': tableName.upper()}
+                continue
+
+            keyVar = members[0]['name']
+            nVar = None
+            valueVar = None
+            if type.value:
+                valueVar = members[1]['name']
+                if len(members) > 2:
+                    nVar = members[2]['name']
+            else:
+                if len(members) > 1:
+                    nVar = members[1]['name']
+
+            print comment
+            print 'void'
+            print '%(s)s_index_set_%(c)s(const struct %(s)s *row, %(args)s)' % \
+                {'s': structName, 'c': columnName,
+                 'args': ', '.join(['%(type)s%(name)s' % m for m in members])}
+            print "{"
+            print "    struct ovsdb_datum *datum = xmalloc(sizeof(struct ovsdb_datum));"
+            if type.n_min == 1 and type.n_max == 1:
+                print "    union ovsdb_atom *key = xmalloc(sizeof(union ovsdb_atom));"
+                if type.value:
+                    print "    union ovsdb_atom *value = xmalloc(sizeof(union ovsdb_atom));"
+                print
+                print "    datum->n = 1;"
+                print "    datum->keys = key;"
+                print "    " + type.key.assign_c_value_casting_away_const("key->%s" % type.key.type.to_string(), keyVar)
+                if type.value:
+                    print "    datum->values = value;"
+                    print "    "+ type.value.assign_c_value_casting_away_const("value->%s" % type.value.type.to_string(), valueVar)
+                else:
+                    print "    datum->values = NULL;"
+                txn_write_func = "ovsdb_idl_index_write_"
+            elif type.is_optional_pointer():
+                print "    union ovsdb_atom *key = xmalloc(sizeof (union ovsdb_atom));"
+                print
+                print "    if (%s) {" % keyVar
+                print "        datum->n = 1;"
+                print "        datum->keys = key;"
+                print "        " + type.key.assign_c_value_casting_away_const("key->%s" % type.key.type.to_string(), keyVar)
+                print "    } else {"
+                print "        datum->n = 0;"
+                print "        datum->keys = NULL;"
+                print "    }"
+                print "    datum->values = NULL;"
+                txn_write_func = "ovsdb_idl_index_write_"
+            elif type.n_max == 1:
+                print "    union ovsdb_atom *key = xmalloc(sizeof(union ovsdb_atom));"
+                print
+                print "    if (%s) {" % nVar
+                print "        datum->n = 1;"
+                print "        datum->keys = key;"
+                print "        " + type.key.assign_c_value_casting_away_const("key->%s" % type.key.type.to_string(), "*" + keyVar)
+                print "    } else {"
+                print "        datum->n = 0;"
+                print "        datum->keys = NULL;"
+                print "    }"
+                print "    datum->values = NULL;"
+                txn_write_func = "ovsdb_idl_index_write_"
+            else:
+                print "    size_t i;"
+                print
+                print "    datum->n = %s;" % nVar
+                print "    datum->keys = %s ? xmalloc(%s * sizeof *datum->keys) : NULL;" % (nVar, nVar)
+                if type.value:
+                    print "    datum->values = xmalloc(%s * sizeof *datum->values);" % nVar
+                else:
+                    print "    datum->values = NULL;"
+                print "    for (i = 0; i < %s; i++) {" % nVar
+                print "        " + type.key.copyCValue("datum->keys[i].%s" % type.key.type.to_string(), "%s[i]" % keyVar)
+                if type.value:
+                    print "        " + type.value.copyCValue("datum->values[i].%s" % type.value.type.to_string(), "%s[i]" % valueVar)
+                print "    }"
+                if type.value:
+                    valueType = type.value.toAtomicType()
+                else:
+                    valueType = "OVSDB_TYPE_VOID"
+                print "    ovsdb_datum_sort_unique(datum, %s, %s);" % (
+                    type.key.toAtomicType(), valueType)
+                txn_write_func = "ovsdb_idl_index_write_"
+            print "    %(f)s(CONST_CAST(struct ovsdb_idl_row *, &row->header_), &%(s)s_columns[ %(S)s_COL_%(C)s ], datum, &%(p)stable_classes[%(P)sTABLE_%(T)s]);" \
+                % {'f': txn_write_func,
+                   's': structName,
+                   'S': structName.upper(),
+                   'C': columnName.upper(),
+                   'p': prefix,
+                   'P': prefix.upper(),
+                   't': tableName,
+                   'T': tableName.upper()}
+            print "}"
+# End Index table related functions
+
+        # Table columns.
+        print "\nstruct ovsdb_idl_column %s_columns[%s_N_COLUMNS];" % (
+            structName, structName.upper())
         print """
 void
 %(s)s_set_condition(struct ovsdb_idl *idl, struct ovsdb_idl_condition *condition)
diff --git a/tests/ovsdb-idl.at b/tests/ovsdb-idl.at
index d2c1ea6..87e9084 100644
--- a/tests/ovsdb-idl.at
+++ b/tests/ovsdb-idl.at
@@ -1300,3 +1300,266 @@  OVSDB_CHECK_IDL_NOTIFY([simple idl verify notify],
 014: i=1 r=123.5 b=false s=mystring u=<3> ia=[1 2 3] ra=[-0.5] ba=[true] sa=[abc def] ua=[<4> <5>] uuid=<0>
 015: done
 ]])
+
+# Tests to verify the functionality of the one column compound index.
+# It tests index for one column string and integer indexes.
+# The run of test-ovsdb generates the output of the display of data using the different indexes defined in
+# the program.
+# Then, some at_checks are used to verify the correctness of the corresponding index as well as the existence
+# of all the rows involved in the test.
+m4_define([OVSDB_CHECK_IDL_COMPOUND_INDEX_SINGLE_COLUMN_C],
+  [AT_SETUP([$1 - C])
+   AT_KEYWORDS([ovsdb server idl compound_index_single_column compound_index positive $5])
+   AT_CHECK([ovsdb_start_idltest])
+   m4_if([$2], [], [],
+     [AT_CHECK([ovsdb-client transact unix:socket $2], [0], [ignore], [ignore], [kill `cat pid`])])
+# Generate the data to be tested.
+   AT_CHECK([test-ovsdb '-vPATTERN:console:test-ovsdb|%c|%m' -vjsonrpc -t10 -c idl-compound-index unix:socket $3],
+            [0], [stdout], [ignore], [kill `cat pid`])
+# Filter the rows of data that corresponds to the string index eliminating the extra columns of data.
+# This is done to verifiy that the output data is in the correct and expected order.
+   AT_CHECK([[cat stdout | grep -oh '[0-9]\{3\}: s=.*' | sed -e 's/ i=.*//g']],
+            [0], [$4], [], [kill `cat pid`])
+# Here, the data is filtered and sorted in order to have all the rows in the index and be
+# able to determined that all the involved rows are present.
+   AT_CHECK([[cat stdout | grep -oh '[0-9]\{3\}: s=.*' | sort -k 1,1n -k 2,2 -k 3,3]],
+            [0], [$5], [], [kill `cat pid`])
+# Filter the rows of data that corresponds to the integer index eliminating the extra columns of data.
+# This is done to verifiy that the output data is in the correct and expected order.
+   AT_CHECK([[cat stdout | grep -oh '[0-9]\{3\}: i=.*' | sed -e 's/ s=.*//g']],
+            [0], [$6], [], [kill `cat pid`])
+# Here again, the data is filtered and sorted in order to have all the rows in the index and be
+# able to determined that all the involved rows are present.
+   AT_CHECK([[cat stdout | grep -oh '[0-9]\{3\}: i=.*' | sort -k 1,1n -k 2,2 -k 3,3]],
+            [0], [$7], [], [kill `cat pid`])
+   OVSDB_SERVER_SHUTDOWN
+   AT_CLEANUP])
+
+OVSDB_CHECK_IDL_COMPOUND_INDEX_SINGLE_COLUMN_C([Compound_index, single column test ],
+    [['["idltest",
+      {"op": "insert", "table": "simple", "row": {"s":"List000", "i": 1, "b":true, "r":101.0}},
+      {"op": "insert", "table": "simple", "row": {"s":"List000", "i": 2, "b":false, "r":102.0}},
+      {"op": "insert", "table": "simple", "row": {"s":"List000", "i": 10, "b":true, "r":110.0}},
+      {"op": "insert", "table": "simple", "row": {"s":"List001", "i": 1, "b":false, "r":110.0}},
+      {"op": "insert", "table": "simple", "row": {"s":"List001", "i": 2, "b":true, "r":120.0}},
+      {"op": "insert", "table": "simple", "row": {"s":"List001", "i": 2, "b":true, "r":122.0}},
+      {"op": "insert", "table": "simple", "row": {"s":"List001", "i": 4, "b":true, "r":130.0}},
+      {"op": "insert", "table": "simple", "row": {"s":"List005", "i": 5, "b":true, "r":130.0}},
+      {"op": "insert", "table": "simple", "row": {"s":"List020", "i": 20, "b":true, "r":220.0}},
+      {"op": "insert", "table": "simple", "row": {"s":"List020", "i": 19, "b":true, "r":219.0}}
+      ]']],
+    [idl_compound_index_single_column],
+    [001: s=List000
+001: s=List000
+001: s=List000
+001: s=List001
+001: s=List001
+001: s=List001
+001: s=List001
+001: s=List005
+001: s=List020
+001: s=List020
+003: s=List001
+003: s=List001
+003: s=List001
+003: s=List001
+],
+[001: s=List000 i=1 b=True r=101.000000
+001: s=List000 i=10 b=True r=110.000000
+001: s=List000 i=2 b=False r=102.000000
+001: s=List001 i=1 b=False r=110.000000
+001: s=List001 i=2 b=True r=120.000000
+001: s=List001 i=2 b=True r=122.000000
+001: s=List001 i=4 b=True r=130.000000
+001: s=List005 i=5 b=True r=130.000000
+001: s=List020 i=19 b=True r=219.000000
+001: s=List020 i=20 b=True r=220.000000
+003: s=List001 i=1 b=False r=110.000000
+003: s=List001 i=2 b=True r=120.000000
+003: s=List001 i=2 b=True r=122.000000
+003: s=List001 i=4 b=True r=130.000000
+],
+[002: i=1
+002: i=1
+002: i=2
+002: i=2
+002: i=2
+002: i=4
+002: i=5
+002: i=10
+002: i=19
+002: i=20
+004: i=5
+005: i=4
+005: i=5
+006: i=5
+006: i=10
+006: i=19
+006: i=20
+006: i=54
+],
+[002: i=1 s=List000 b=True r=101.000000
+002: i=1 s=List001 b=False r=110.000000
+002: i=10 s=List000 b=True r=110.000000
+002: i=19 s=List020 b=True r=219.000000
+002: i=2 s=List000 b=False r=102.000000
+002: i=2 s=List001 b=True r=120.000000
+002: i=2 s=List001 b=True r=122.000000
+002: i=20 s=List020 b=True r=220.000000
+002: i=4 s=List001 b=True r=130.000000
+002: i=5 s=List005 b=True r=130.000000
+004: i=5 s=List005 b=True r=130.000000
+005: i=4 s=List001 b=True r=130.000000
+005: i=5 s=List005 b=True r=130.000000
+006: i=10 s=List000 b=True r=110.000000
+006: i=19 s=List020 b=True r=219.000000
+006: i=20 s=List020 b=True r=220.000000
+006: i=5 s=List005 b=True r=130.000000
+006: i=54 s=Lista054 b=False r=0.000000
+])
+
+# Tests to verify the functionality of two column compound index.
+# It tests index for two columns using string and integer fields.
+# The run of test-ovsdb generates the output of the display of data using the different indexes defined in
+# the program.
+# Then, some at_checks are used to verify the correctness of the corresponding index as well as the existence
+# of all the rows involved in the test.
+m4_define([OVSDB_CHECK_IDL_COMPOUND_INDEX_DOUBLE_COLUMN_C],
+  [AT_SETUP([$1 - C])
+   AT_KEYWORDS([ovsdb server idl compound_index_double_column compound_index positive $5])
+   AT_CHECK([ovsdb_start_idltest])
+   m4_if([$2], [], [],
+     [AT_CHECK([ovsdb-client transact unix:socket $2], [0], [ignore], [ignore], [kill `cat pid`])])
+# Generate the data to be tested.
+   AT_CHECK([test-ovsdb '-vPATTERN:console:test-ovsdb|%c|%m' -vjsonrpc -t10 -c idl-compound-index unix:socket $3],
+            [0], [stdout], [ignore], [kill `cat pid`])
+# Filter the rows of data that corresponds to the string-integer index eliminating the extra columns of data.
+# This is done to verifiy that the output data is in the correct and expected order.
+   AT_CHECK([[cat stdout | grep -oh '[0-9]\{3\}: s=.*' | sed -e 's/ b=.*//g']],
+            [0], [$4], [], [kill `cat pid`])
+# Here, the data is filtered and sorted in order to have all the rows in the index and be
+# able to determined that all the involved rows are present.
+   AT_CHECK([[cat stdout | grep -oh '[0-9]\{3\}: s=.*' | sort -k 1,1n -k 2,2 -k 3,3]],
+            [0], [$5], [], [kill `cat pid`])
+# Filter the rows of data that corresponds to the integer index eliminating the extra columns of data.
+# This is done to verifiy that the output data is in the correct and expected order.
+   AT_CHECK([[cat stdout | grep -oh '[0-9]\{3\}: i=.*' | sed -e 's/ b=.*//g']],
+            [0], [$6], [], [kill `cat pid`])
+# Here again, the data is filtered and sorted in order to have all the rows in the index and be
+# able to determined that all the involved rows are present.
+   AT_CHECK([[cat stdout | grep -oh '[0-9]\{3\}: i=.*' | sort -k 1,1n -k 2,2 -k 3,3]],
+            [0], [$7], [], [kill `cat pid`])
+   OVSDB_SERVER_SHUTDOWN
+   AT_CLEANUP])
+
+OVSDB_CHECK_IDL_COMPOUND_INDEX_DOUBLE_COLUMN_C([Compound_index, double column test ],
+    [['["idltest",
+      {"op": "insert", "table": "simple", "row": {"s":"List000", "i": 1, "b":true, "r":101.0}},
+      {"op": "insert", "table": "simple", "row": {"s":"List000", "i": 2, "b":false, "r":102.0}},
+      {"op": "insert", "table": "simple", "row": {"s":"List000", "i": 10, "b":true, "r":110.0}},
+      {"op": "insert", "table": "simple", "row": {"s":"List001", "i": 1, "b":false, "r":110.0}},
+      {"op": "insert", "table": "simple", "row": {"s":"List001", "i": 2, "b":true, "r":120.0}},
+      {"op": "insert", "table": "simple", "row": {"s":"List001", "i": 2, "b":true, "r":122.0}},
+      {"op": "insert", "table": "simple", "row": {"s":"List001", "i": 4, "b":true, "r":130.0}},
+      {"op": "insert", "table": "simple", "row": {"s":"List005", "i": 5, "b":true, "r":130.0}},
+      {"op": "insert", "table": "simple", "row": {"s":"List020", "i": 20, "b":true, "r":220.0}},
+      {"op": "insert", "table": "simple", "row": {"s":"List020", "i": 19, "b":true, "r":219.0}}
+      ]']],
+    [idl_compound_index_double_column],
+    [001: s=List000 i=1
+001: s=List000 i=2
+001: s=List000 i=10
+001: s=List001 i=1
+001: s=List001 i=2
+001: s=List001 i=2
+001: s=List001 i=4
+001: s=List005 i=5
+001: s=List020 i=19
+001: s=List020 i=20
+002: s=List000 i=10
+002: s=List000 i=2
+002: s=List000 i=1
+002: s=List001 i=4
+002: s=List001 i=2
+002: s=List001 i=2
+002: s=List001 i=1
+002: s=List005 i=5
+002: s=List020 i=20
+002: s=List020 i=19
+003: s=List000 i=10
+004: s=List001 i=1
+004: s=List001 i=2
+004: s=List001 i=2
+004: s=List001 i=4
+004: s=List005 i=5
+],
+    [001: s=List000 i=1 b=True r=101.000000
+001: s=List000 i=10 b=True r=110.000000
+001: s=List000 i=2 b=False r=102.000000
+001: s=List001 i=1 b=False r=110.000000
+001: s=List001 i=2 b=True r=120.000000
+001: s=List001 i=2 b=True r=122.000000
+001: s=List001 i=4 b=True r=130.000000
+001: s=List005 i=5 b=True r=130.000000
+001: s=List020 i=19 b=True r=219.000000
+001: s=List020 i=20 b=True r=220.000000
+002: s=List000 i=1 b=True r=101.000000
+002: s=List000 i=10 b=True r=110.000000
+002: s=List000 i=2 b=False r=102.000000
+002: s=List001 i=1 b=False r=110.000000
+002: s=List001 i=2 b=True r=120.000000
+002: s=List001 i=2 b=True r=122.000000
+002: s=List001 i=4 b=True r=130.000000
+002: s=List005 i=5 b=True r=130.000000
+002: s=List020 i=19 b=True r=219.000000
+002: s=List020 i=20 b=True r=220.000000
+003: s=List000 i=10 b=True r=110.000000
+004: s=List001 i=1 b=False r=110.000000
+004: s=List001 i=2 b=True r=120.000000
+004: s=List001 i=2 b=True r=122.000000
+004: s=List001 i=4 b=True r=130.000000
+004: s=List005 i=5 b=True r=130.000000
+],
+    [005: i=1 s=List000
+005: i=1 s=List001
+005: i=2 s=List000
+005: i=2 s=List001
+005: i=2 s=List001
+005: i=4 s=List001
+005: i=5 s=List005
+005: i=10 s=List000
+005: i=19 s=List020
+005: i=20 s=List020
+006: i=20 s=List020
+006: i=19 s=List020
+006: i=10 s=List000
+006: i=5 s=List005
+006: i=4 s=List001
+006: i=2 s=List000
+006: i=2 s=List001
+006: i=2 s=List001
+006: i=1 s=List000
+006: i=1 s=List001
+],
+    [005: i=1 s=List000 b=True r=101.000000
+005: i=1 s=List001 b=False r=110.000000
+005: i=10 s=List000 b=True r=110.000000
+005: i=19 s=List020 b=True r=219.000000
+005: i=2 s=List000 b=False r=102.000000
+005: i=2 s=List001 b=True r=120.000000
+005: i=2 s=List001 b=True r=122.000000
+005: i=20 s=List020 b=True r=220.000000
+005: i=4 s=List001 b=True r=130.000000
+005: i=5 s=List005 b=True r=130.000000
+006: i=1 s=List000 b=True r=101.000000
+006: i=1 s=List001 b=False r=110.000000
+006: i=10 s=List000 b=True r=110.000000
+006: i=19 s=List020 b=True r=219.000000
+006: i=2 s=List000 b=False r=102.000000
+006: i=2 s=List001 b=True r=120.000000
+006: i=2 s=List001 b=True r=122.000000
+006: i=20 s=List020 b=True r=220.000000
+006: i=4 s=List001 b=True r=130.000000
+006: i=5 s=List005 b=True r=130.000000
+])
+
diff --git a/tests/test-ovsdb.c b/tests/test-ovsdb.c
index 968c1de..aded537 100644
--- a/tests/test-ovsdb.c
+++ b/tests/test-ovsdb.c
@@ -215,7 +215,14 @@  usage(void)
            "  idl-partial-update-set-column SERVER \n"
            "    connect to SERVER and executes different operations to\n"
            "    test the capacity of updating elements inside a set column\n"
-           "    displaying the table information after each operation.\n",
+           "    displaying the table information after each operation.\n"
+           "  idl-compound-index TEST_TO_EXECUTE\n"
+           "    Execute the tests to verify compound-index feature.\n"
+           "    The TEST_TO_EXECUTE are:\n"
+           "        idl_compound_index_single_column:\n"
+           "            test for indexes using one column as part of the index.\n"
+           "        idl_compound_index_double_column:\n"
+           "            test for indexes using two columns as part of index.\n",
            program_name, program_name);
     vlog_usage();
     printf("\nOther options:\n"
@@ -2635,6 +2642,236 @@  do_idl_partial_update_set_column(struct ovs_cmdl_context *ctx)
     return;
 }
 
+static int
+test_idl_compound_index_single_column(struct ovsdb_idl *idl,
+        struct ovsdb_idl_index_cursor* sCursor,
+        struct ovsdb_idl_index_cursor* iCursor)
+{
+    const struct idltest_simple* myRow;
+    struct ovsdb_idl_txn *txn;
+    int step=0;
+
+     /* Display records by string index -> sCursor */
+     ++step;
+     IDLTEST_SIMPLE_FOR_EACH_BYINDEX(myRow, sCursor)
+     {
+         printf("%03d: s=%s i=%"PRId64" b=%s r=%f\n", step, myRow->s, myRow->i, myRow->b?"True":"False", myRow->r);
+     }
+     /* Display records by integer index -> iCursor */
+     ++step;
+     IDLTEST_SIMPLE_FOR_EACH_BYINDEX(myRow, iCursor)
+     {
+         printf("%03d: i=%"PRId64" s=%s b=%s r=%f\n", step,  myRow->i,myRow->s, myRow->b?"True":"False", myRow->r);
+     }
+     /* Display records by string index -> sCursor with filtering where s=\"List001\ */
+     ++step;
+     struct idltest_simple *equal = idltest_simple_index_init_row(idl, &idltest_table_simple);
+     idltest_simple_index_set_s(equal, "List001");
+     assert(strcmp(equal->s, "List001") == 0);
+     IDLTEST_SIMPLE_FOR_EACH_EQUAL(myRow, sCursor, equal)
+     {
+         printf("%03d: s=%s i=%"PRId64" b=%s r=%f\n", step, myRow->s, myRow->i, myRow->b?"True":"False", myRow->r);
+     }
+     /* Display records by integer index -> iCursor with filtering where i=5 */
+     ++step;
+     idltest_simple_index_set_i(equal, 5);
+     assert(equal->i == 5);
+     IDLTEST_SIMPLE_FOR_EACH_EQUAL(myRow, iCursor, equal) {
+         printf("%03d: i=%"PRId64" s=%s b=%s r=%f\n", step,  myRow->i,myRow->s, myRow->b?"True":"False", myRow->r);
+     }
+     /* Display records by integer index -> iCursor in range i=[3,7] */
+     ++step;
+     struct idltest_simple *from, *to;
+     from = idltest_simple_index_init_row(idl, &idltest_table_simple);
+     idltest_simple_index_set_i(from, 3);
+     assert(from->i == 3);
+     to = idltest_simple_index_init_row(idl, &idltest_table_simple);
+     idltest_simple_index_set_i(to, 7);
+     assert(to->i == 7);
+     IDLTEST_SIMPLE_FOR_EACH_RANGE(myRow, iCursor, from, to)
+     {
+         printf("%03d: i=%"PRId64" s=%s b=%s r=%f\n", step,  myRow->i,myRow->s, myRow->b?"True":"False", myRow->r);
+     }
+     /* Delete record i=4 and insert i=54 by integer index -> iCursor */
+     ++step;
+     struct idltest_simple *toDelete, *toInsert;
+     toDelete = idltest_simple_index_init_row(idl, &idltest_table_simple);
+     idltest_simple_index_set_i(toDelete, 4);
+     assert(toDelete->i == 4);
+     myRow = idltest_simple_index_find(iCursor, toDelete);
+     assert(myRow);
+     assert(myRow->i == 4);
+     txn = ovsdb_idl_txn_create(idl);
+     idltest_simple_delete(myRow);
+     toInsert = idltest_simple_insert(txn);
+     idltest_simple_set_i(toInsert, 54);
+     idltest_simple_set_s(toInsert, "Lista054");
+     ovsdb_idl_txn_commit_block(txn);
+     ovsdb_idl_txn_destroy(txn);
+     idltest_simple_index_set_i(to, 60);
+     printf("Expected 60, stored %"PRId64"\n", to->i);
+     assert(to->i == 60);
+     IDLTEST_SIMPLE_FOR_EACH_RANGE(myRow, iCursor, from, to)
+     {
+         printf("%03d: i=%"PRId64" s=%s b=%s r=%f\n", step,  myRow->i, myRow->s, myRow->b?"True":"False", myRow->r);
+     }
+
+     /* Free the temporal rows */
+     idltest_simple_index_destroy_row(from);
+     idltest_simple_index_destroy_row(to);
+     idltest_simple_index_destroy_row(equal);
+     return step;
+}
+
+static int
+test_idl_compound_index_double_column(struct ovsdb_idl *idl,
+        struct ovsdb_idl_index_cursor* siCursor,
+        struct ovsdb_idl_index_cursor* sidCursor,
+        struct ovsdb_idl_index_cursor* isCursor,
+        struct ovsdb_idl_index_cursor* idsCursor)
+{
+    const struct idltest_simple* myRow;
+    int step = 0;
+
+    /* Display records by string-integer index -> siCursor */
+    step++;
+    IDLTEST_SIMPLE_FOR_EACH_BYINDEX(myRow, siCursor)
+    {
+        printf("%03d: s=%s i=%"PRId64" b=%s r=%f\n", step, myRow->s, myRow->i, myRow->b?"True":"False", myRow->r);
+    }
+    /* Display records by string-integer(down order) index -> sidCursor */
+    step++;
+    IDLTEST_SIMPLE_FOR_EACH_BYINDEX(myRow, sidCursor)
+    {
+        printf("%03d: s=%s i=%"PRId64" b=%s r=%f\n", step, myRow->s, myRow->i, myRow->b?"True":"False", myRow->r);
+    }
+    /* Display records by string-integer index -> siCursor with filtering where s="List000" and i=10 */
+    step++;
+    struct idltest_simple *equal = idltest_simple_index_init_row(idl, &idltest_table_simple);
+    idltest_simple_index_set_s(equal, "List000");
+    assert(strcmp(equal->s, "List000") == 0);
+    idltest_simple_index_set_i(equal, 10);
+    assert(equal->i == 10);
+    IDLTEST_SIMPLE_FOR_EACH_EQUAL(myRow, siCursor, equal)
+    {
+        printf("%03d: s=%s i=%"PRId64" b=%s r=%f\n", step, myRow->s, myRow->i, myRow->b?"True":"False", myRow->r);
+    }
+    /* Display records by string-integer index -> siCursor in range i=[0,100] and s=[\"List002\",\"List003\"] */
+    step++;
+    struct idltest_simple *from, *to;
+    from =  idltest_simple_index_init_row(idl, &idltest_table_simple);
+    to = idltest_simple_index_init_row(idl, &idltest_table_simple);
+    idltest_simple_index_set_i(from, 0);
+    assert(from->i == 0);
+    idltest_simple_index_set_s(from, "List001");
+    assert(strcmp(from->s, "List001") == 0);
+    idltest_simple_index_set_i(to, 100);
+    assert(to->i == 100);
+    idltest_simple_index_set_s(to, "List005");
+    assert(strcmp(to->s, "List005")==0);
+    IDLTEST_SIMPLE_FOR_EACH_RANGE(myRow, siCursor, from, to)
+    {
+        printf("%03d: s=%s i=%"PRId64" b=%s r=%f\n", step, myRow->s, myRow->i, myRow->b?"True":"False", myRow->r);
+    }
+    /* Display records using integer-string index. */
+    step++;
+    IDLTEST_SIMPLE_FOR_EACH_BYINDEX(myRow, isCursor) {
+        printf("%03d: i=%"PRId64" s=%s b=%s r=%f\n", step, myRow->i, myRow->s, myRow->b?"True":"False", myRow->r);
+    }
+    /* Display records using integer(descend)-string index. */
+    step++;
+    IDLTEST_SIMPLE_FOR_EACH_BYINDEX(myRow, idsCursor) {
+        printf("%03d: i=%"PRId64" s=%s b=%s r=%f\n", step, myRow->i, myRow->s, myRow->b?"True":"False", myRow->r);
+    }
+
+    idltest_simple_index_destroy_row(to);
+    idltest_simple_index_destroy_row(from);
+    idltest_simple_index_destroy_row(equal);
+    return step;
+}
+
+static void
+do_idl_compound_index(struct ovs_cmdl_context *ctx)
+{
+    struct ovsdb_idl *idl;
+    struct ovsdb_idl_index_cursor sCursor, iCursor, siCursor, sidCursor,
+                    isCursor, idsCursor;
+    enum TESTS { IDL_COMPOUND_INDEX_WITH_SINGLE_COLUMN,
+            IDL_COMPOUND_INDEX_WITH_DOUBLE_COLUMN
+    };
+    int step = 0;
+    int i;
+
+    idl = ovsdb_idl_create(ctx->argv[1], &idltest_idl_class, false, true);
+
+    /* Add tables/columns and initialize index data needed for tests */
+    ovsdb_idl_add_table(idl, &idltest_table_simple);
+    ovsdb_idl_add_column(idl, &idltest_simple_col_s);
+    ovsdb_idl_add_column(idl, &idltest_simple_col_i);
+    ovsdb_idl_add_column(idl, &idltest_simple_col_r);
+    ovsdb_idl_add_column(idl, &idltest_simple_col_b);
+
+    struct ovsdb_idl_index *index;
+    index = ovsdb_idl_create_index(idl, &idltest_table_simple, "string");
+    ovsdb_idl_index_add_column(index, &idltest_simple_col_s, OVSDB_INDEX_ASC, NULL);
+
+    index = ovsdb_idl_create_index(idl, &idltest_table_simple, "integer");
+    ovsdb_idl_index_add_column(index, &idltest_simple_col_i, OVSDB_INDEX_ASC, NULL);
+
+    index = ovsdb_idl_create_index(idl, &idltest_table_simple, "string-integer");
+    ovsdb_idl_index_add_column(index, &idltest_simple_col_s, OVSDB_INDEX_ASC, NULL);
+    ovsdb_idl_index_add_column(index, &idltest_simple_col_i, OVSDB_INDEX_ASC, NULL);
+
+    index = ovsdb_idl_create_index(idl, &idltest_table_simple, "string-integerd");
+    ovsdb_idl_index_add_column(index, &idltest_simple_col_s, OVSDB_INDEX_ASC, NULL);
+    ovsdb_idl_index_add_column(index, &idltest_simple_col_i, OVSDB_INDEX_DESC, NULL);
+
+    index = ovsdb_idl_create_index(idl, &idltest_table_simple, "integer-string");
+    ovsdb_idl_index_add_column(index, &idltest_simple_col_i, OVSDB_INDEX_ASC, NULL);
+    ovsdb_idl_index_add_column(index, &idltest_simple_col_s, OVSDB_INDEX_ASC, NULL);
+
+    index = ovsdb_idl_create_index(idl, &idltest_table_simple, "integerd-string");
+    ovsdb_idl_index_add_column(index, &idltest_simple_col_i, OVSDB_INDEX_DESC, NULL);
+    ovsdb_idl_index_add_column(index, &idltest_simple_col_s, OVSDB_INDEX_ASC, NULL);
+
+    /* wait for replica to be updated */
+    ovsdb_idl_get_initial_snapshot(idl);
+
+    /* Initialize cursors to be used by indexes */
+    ovsdb_idl_initialize_cursor(idl, &idltest_table_simple, "string", &sCursor);
+    ovsdb_idl_initialize_cursor(idl, &idltest_table_simple, "integer", &iCursor);
+    ovsdb_idl_initialize_cursor(idl, &idltest_table_simple, "string-integer", &siCursor);
+    ovsdb_idl_initialize_cursor(idl, &idltest_table_simple, "string-integerd", &sidCursor);
+    ovsdb_idl_initialize_cursor(idl, &idltest_table_simple, "integer-string", &isCursor);
+    ovsdb_idl_initialize_cursor(idl, &idltest_table_simple, "integerd-string", &idsCursor);
+
+    setvbuf(stdout, NULL, _IONBF, 0);
+    int test_to_run = -1;
+    for (i = 2; i < ctx->argc; i++) {
+        char *arg = ctx->argv[i];
+
+        if(strcmp(arg,"idl_compound_index_single_column")== 0) {
+            test_to_run = IDL_COMPOUND_INDEX_WITH_SINGLE_COLUMN;
+        } else if(strcmp(arg, "idl_compound_index_double_column")==0) {
+            test_to_run = IDL_COMPOUND_INDEX_WITH_DOUBLE_COLUMN;
+        }
+
+        switch(test_to_run) {
+            case IDL_COMPOUND_INDEX_WITH_SINGLE_COLUMN:
+                test_idl_compound_index_single_column(idl, &sCursor, &iCursor);
+                break;
+            case IDL_COMPOUND_INDEX_WITH_DOUBLE_COLUMN:
+                test_idl_compound_index_double_column(idl, &siCursor,
+                        &sidCursor, &isCursor, &idsCursor);
+                break;
+            default:
+                printf("%03d: Test %s not implemented.\n", step++, arg);
+        }
+    }
+    ovsdb_idl_destroy(idl);
+    printf("%03d: done\n", step);
+}
+
 static struct ovs_cmdl_command all_commands[] = {
     { "log-io", NULL, 2, INT_MAX, do_log_io, OVS_RO },
     { "default-atoms", NULL, 0, 0, do_default_atoms, OVS_RO },
@@ -2666,6 +2903,7 @@  static struct ovs_cmdl_command all_commands[] = {
     { "execute-readonly", NULL, 2, INT_MAX, do_execute_ro, OVS_RO },
     { "trigger", NULL, 2, INT_MAX, do_trigger, OVS_RO },
     { "idl", NULL, 1, INT_MAX, do_idl, OVS_RO },
+    { "idl-compound-index", NULL, 2, 2, do_idl_compound_index, OVS_RW },
     { "idl-partial-update-map-column", NULL, 1, INT_MAX,
         do_idl_partial_update_map_column, OVS_RO },
     { "idl-partial-update-set-column", NULL, 1, INT_MAX,