0

I'm trying to get a vector of row from SOCI, but I can't seem to work it out.

I need a function to return a vector of row data from a sql statement. What I think is the right approach:

vector<row> GetRows(string input)
{
    session sql(*soci::factory_odbc(), _connectionString);

    row r;
    statement st = (sql.prepare << input, into(r));
    st.execute();
    vector<row> rows;
    while (st.fetch())
    {
        rows.push_back(r);
    }
    return(rows);
}

This will not compile.

I have to index to the rows, I can't see how to this to work.

Update:

I don't have that much expirence with C++ so I ended up using a simple solution:

typedef boost::variant<boost::blank, int, std::string, double, std::tm, long long, unsigned long long> tField;
typedef std::vector<tField> tRow;
typedef std::vector<tRow> tRows;

Where tField is a boost::variant and the row (tRow) is a vector of those. The dataset (tRows) is then a vector of these.

I ended up with this, not so simple but working solition:

tRows DataAccess::spGetListenSample(const string input)
{
    session sql(*soci::factory_odbc(), _connectionString);

    rowset<row> rs = (sql.prepare << input);

    tRows rows;

    for (rowset<row>::const_iterator it = rs.begin(); it != rs.end(); ++it)
    {
        row const& r = *it;
        if (rows.size() == 0)
        {
            tRow record;
            for (std::size_t i = 0; i != r.size(); ++i)
            {
                const column_properties & props = r.get_properties(i);
                tField field = props.get_name();
                record.push_back(field);
            }
            rows.push_back(record);
        }
        tRow record;
        for (std::size_t i = 0; i != r.size(); ++i)
        {
            const column_properties & props = r.get_properties(i);
            tField field;
            if (r.get_indicator(i) != soci::i_null)
            {
                switch (props.get_data_type())
                {
                case dt_string:
                    field = r.get<std::string>(i);
                    break;
                case dt_double:
                    field = r.get<double>(i);
                    break;
                case dt_integer:
                    field = r.get<int>(i);
                    break;
                case dt_long_long:
                    field = r.get<long long>(i);
                    break;
                case dt_unsigned_long_long:
                    field = r.get<unsigned long long>(i);
                    break;
                case dt_date:
                    std::tm when = r.get<std::tm>(i);
                    field = asctime(&when);
                    break;
                }
            }
            record.push_back(field);
        }
        rows.push_back(record);
    }

    return(rows);
}
  • What exactly does your compiler say? – Wum Mar 06 '18 at 11:12
  • Error C2248 'soci::row::row': cannot access private member declared in class 'soci::row' – Jens Gotthardsen Mar 06 '18 at 11:44
  • Values used to `push_back` on a vector need to be copyable or movable. This seems not to be the case for soci::row and/or its members. – Wum Mar 06 '18 at 12:03
  • I know nothing about SOCI and its capabilities but here's an attempt: If you for each `st.fetch()` can supply a different `row` instance (like `st.into(r)`) then you could use a `std::list` or a `std::deque` instead. They can grow without their value type being move or copy constructable. Before each `st.fetch()` you emplace a new (default constructed) `row` into `rows` and do like `st.into(rows.back())`. If you must use a `std::vector` and know how many rows there are (say `n`), you could construct `rows` as `vector rows (n);` and before each `st.fetch()` do `st.into(rows.at(i));`. –  Mar 06 '18 at 14:20

1 Answers1

2

You cannot push_back values of type soci::row to a std::vector since class soci::row is marked SOCI_NOT_COPYABLE(row).

Wum
  • 306
  • 1
  • 10