Search code examples
c++rdbmssoci

How to code for SELECT * with SOCI?


In most examples for SOCI, the caller must know the fields and types in a query and specifies them through a soci::rowset<> of boost::tuple<> or through some other means.

Is there a way to code without knowing the types and number of columns beforehand, as in a SELECT * FROM ... query?

If so, could you post a short example?


Solution

  • soci::rowset<soci::row> is exactly what you need — soci::row provides dynamic binding.

    From the docs:

    For certain applications it is desirable to be able to select data from arbitrarily structured tables (e.g. via "select * from ...") and format the resulting data based upon its type. SOCI supports this through the soci::row and soci::column_properties classes.

    See:

    http://soci.sourceforge.net/doc/3.2/exchange.html#dynamic
    http://soci.sourceforge.net/doc/3.2/statements.html#rowset

    for details.

    Excerpt from the documentation:

    For example, the code below creates an XML document from a selected row of data from an arbitrary table:

    row r;
    sql << "select * from some_table", into(r);
    
    std::ostringstream doc;
    doc << "<row>" << std::endl;
    for(std::size_t i = 0; i != r.size(); ++i)
    {
        const column_properties & props = r.get_properties(i);
    
        doc << '<' << props.get_name() << '>';
    
        switch(props.get_data_type())
        {
        case dt_string:
            doc << r.get<std::string>(i);
            break;
        case dt_double:
            doc << r.get<double>(i);
            break;
        case dt_integer:
            doc << r.get<int>(i);
            break;
        case dt_long_long:
            doc << r.get<long long>(i);
            break;
        case dt_unsigned_long_long:
            doc << r.get<unsigned long long>(i);
            break;
        case dt_date:
            std::tm when = r.get<std::tm>(i);
            doc << asctime(&when);
            break;
        }
    
        doc << "</" << props.get_name() << '>' << std::endl;
    }
    doc << "</row>";
    

    The type T parameter that should be passed to row::get() depends on the SOCI data type that is returned from column_properties::get_data_type().