Vector parameters

std::vector<std::string> titles={"Hare Brush", "Hare Tonic"};
std::pair<std::vector<double>,
          std::vector<x::sql::bitflag>> prices={
      std::vector<double>({0.99, 0}),
      std::vector<x::sql::bitflag>({0, 1})
};

std::vector<x::sql::bitflag> status;
status.resize(2);

auto stmt=conn->prepare("insert into videos(titles, prices) values(?, ?)");

try {
    stmt->execute_vector(status, titles, prices);
} catch (...) {
    // ...
}

if (!(status[0] & 1) ||
     !(status[1] & 1))
     // ...

execute_vector() executes the prepared statement with multiple sets of parameters. This is usually used to bulk-insert rows into a table. The parameter values are given as vectors. Each vector specifies the value for the corresponding parameter in each row. It's a column vector.

All vectors, including the first parameter, must be of the same size. The first parameter is a status vector, of x::sql::bitflag. When execute_vector() returns, each x::sql::bitflag reports what happened to that row. The lowest bit indicates whether the row was processed, with the entire value of the bitflag giving more detail. The possible numerical values are:

0

Unspecified error. The SQL statement probably had an error in it.

1

This row was processed.

2

This row was not processed as a result of another error, some database drivers stop when an error occured processing one row, and will not process the remaining rows.

3

This row processed, with modifications (usually a truncated string value, with some database drivers, other database drivers truncate silently).

The numerical values are subject to change. An error is usually indicated by a thrown exception, but the status vector gets initialized in all cases.

The remaining parameters are any combination of:

A std::vector

Specifies a non-NULL value of this parameter in each row.

A std::pair of two std::vectors

Specifies a non-NULL value of this parameter in each row from the first vector when the corresponding value in the second vector is zero; or a NULL value for this row if the second vector's value for this row is non-zero.

A std::list of std::vectors

This is equivalent to specifying each std::vector directly as a parameter to execute_vector().

A std::list of std::pair of two std::vectors

This is equivalent to specifying each std::pair directly as a parameter to execute_vector().

When a std::pair of vectors gets specified, the second vector in the pair is always a vector of x::sql::bitflags. A non-zero value specifies a NULL value for the corresponding row's value of its column parameter. A zero takes the value for that row from the corresponding value in the first vector. Specifying just a vector, instead of a std::pair of vectors, has the effect of specifying non-NULL values for all rows of that column.

Note

The underlying ODBC API is a C API. A vector of C++ std::strings must be copied into a single buffer which uses the same fixed size for each string value. execute_vector() automatically takes the longest string in the vector, and allocates the appropriate buffer.

But this means that if one of the strings in a 1000-element string vector is 100 characters long, this creates a char[100*1000] buffer, even if all other strings are only one character long.

x::sql::statement stmt=conn->prepare("INSERT INTO books(name, price) VALUES(?, ?)");
x::sql::bitflag result=stmt->execute("Around the world in 80 days", 9.99);

Technically, a non-vector execute is equivalent to a vector execute with a one-row vector, with execute() returning the sole row's status. Since an error executing an SQL statement usually results in a thrown exception, the expected return value should always indicate a success.

x::sql::bitflag result;

x::sql::statement stmt=conn->execute(result, "INSERT INTO books(name, price) VALUES(?, ?)", "Around the world in 80 days", 9.99);

A connection handle's execute() optionally takes an x::sql::bitflag lvalue parameter, before the SQL statement. This sets the lvalue to the return value from the real execute(), with the same caveats.