Using Sequences in C++

As explained in the User's Guide page, a sequence is an unbounded array of eXtremeDB-supported scalar data elements. The C++ Sequence class is used together with the generated C API classname_fieldname_*() functions in C++ applications to manage database fields of type sequence. As sequences are effectively vectors of values, they are accessed through iterators. Whereas the C type mco_seq_iterator_h is used in C applications, the C++ class Sequence serves the equivalent role in C++ applications. The Sequence class provides a powerful set of Analytics Methods for performing mathematical and statistical operations on sequences.

Inserting and Updating Sequences

Normally sequence data is inserted using the generated C API classname_fieldname_append(). For example consider the following schema definition:

 
    #define uint4 unsigned<4>
     
    class Quote {
        char<16>            symbol;
        sequence<uint4 asc> day;
        sequence<float>     price;
         
        tree<symbol> by_symbol;
    };
     

With this class definition, the Quote sequence fields day and price can be populated with code like the following:

 
    #define  N_ITEMS                4
    uint4 days[N_ITEMS] = { 1, 2, 4, 5 };
    float prices[N_ITEMS] = { 10, 20, 40 ,50 };
    ...
    Quote q;
    q.create(t);
    q.symbol_put("IBM", (uint2)(strlen("IBM")));
    q.day_append(days, N_ITEMS);
    ...
    q.price_append(prices, N_ITEMS);
     

It may sometimes be necessary to insert values into an ordered time series. Values can be inserted into an existing sequence using the generated C API <classname>_<fieldname>_insert(). For example, the following code snippet searches for the Quote object with symbol "IBM", then inserts day and price values:

 
    #define  DAY_THREE              3
    #define  DAY_THREE_PRICE        30
    uint4 day_to_insert[1] = { DAY_THREE };
    float price_to_insert[1] = { DAY_THREE_PRICE };
    ...
    mco_trans_h     t;
    mco_cursor_t    cur;
    ...
    mco_trans_start(db, MCO_READ_WRITE, MCO_TRANS_FOREGROUND, &t);
    mco_cursor_first(t, &cur);
    rc = Quote::by_symbol::cursor(t, &cur);
    if (MCO_S_OK == rc)
    {
        rc = Quote::by_symbol::search(t, &cur, MCO_GE, "IBM", 
                        (uint2)(sizeof("IBM")));
        if (MCO_S_OK == rc)
        {
            //insert here
            Quote q;
            q.create(t);
 
            rc = q.from_cursor(t, &cur);
            Sequence<uint4> seq = q.day_iterator();
            if (MCO_S_OK == rc)
            {
                rc = q.day_search(seq, 
                            DAY_THREE, MCO_SEQ_BOUNDARY_EXCLUSIVE, 
                            0, MCO_SEQ_BOUNDARY_OPEN);
                mco_seq_no_t pos = seq.iter->first_seq_no;
                rc = q.day_insert(pos, day_to_insert, 1);
                ...
                rc = q.price_insert(pos, price_to_insert, 1);
                rc = mco_trans_commit(t);
            }
        }
    }
     

Iterating Sequences

Normally sequence data is iterated using the Sequence method next(). For example, the Quote sequence fields day and price can be iterated with code like the following:

 
    mco_trans_h trans;
    MCO_RET rc;
    ...
    mco_trans_start(db, MCO_READ_ONLY, MCO_TRANS_FOREGROUND, &trans);
    if ( MCO_S_OK == rc )
    {
        Sequence<uint4> day_iterator;
        ...
        quote.day_search(day_iterator, DMY(1,1,2013), MCO_SEQ_BOUNDARY_INCLUSIVE, DMY(1,4,2013), MCO_SEQ_BOUNDARY_INCLUSIVE));
        Sequence<float> price_iterator = quote.price_project(day_iterator);
 
        /* Iterate day and price sequences */
        while (day_iterator.next(day)) 
        {
            printf("%u: %f\n", day, ++price_iterator);
        }
        mco_trans_rollback(trans);
    }
     

Note how the next() method is used to iterate through the day sequence and the convenient ++ operator is used to iterate the price sequence.

Using Analytics Methods

As mentione above, the Sequence class provides a number of Analytics Methods to efficiently manipulate sequence data and perform a variety of statistical operations. For example, the following code snippet demonstrates how to iterate a Grid Aggregate Maximum sequence of Quote price values using a generic sequence output function print_sequence() (as demonstrated in SDK sample samples/native/sequences/api/cpp):

     
    mco_trans_h trans;
    MCO_RET rc;
    ...
    mco_trans_start(db, MCO_READ_ONLY, MCO_TRANS_FOREGROUND, &trans);
    if ( MCO_S_OK == rc )
    {
        /* Iterate through all Quote objects */
        Quote::by_sym::cursor(trans, &quote_cursor);
        for (rc = mco_cursor_first(trans, &quote_cursor); 
            rc != MCO_S_CURSOR_END; 
            rc = mco_cursor_next(trans, &quote_cursor)) 
        {
            /* Get current Quote object */
            quote.from_cursor(trans, &quote_cursor);
 
            /* Print the Grid Aggregate sequence for price */
            print_sequence(quote, quote.price_iterator().gridAggMax(7));
        }
        mco_trans_rollback(trans);
    }
     

Note that the C type sequence_iterator returned by generated function quote.price_iterator() is converted to a C++ Sequence and its method gridAggMax() is invoked in the call to function print_sequence(). This Sequence is then iterated and printed out in print_sequence().