Most databases implement a custom “blob” datatype for
defining a table field that contains a large text or a binary chunk, or
a blob.
Inserting a blob is done by defining an beginning and an ending iterator
for a char
sequence that defines a text blob, or
an unsigned char
sequence that defines a binary
blob.
Similarly, retrieving a blob involves defining an output iterator, which
gets iterated over the contents of the blob field.
It's possible that some database drivers may require input iterators to be, at least, forward iterators, and will have poor performance unless they are random access iterators.
#include <x/sql/insertblob.H> int memo_id; auto stmt=conn->prepare("INSERT INTO memos(memo_id, memo_text) VALUES(?, ?)"); stmt->execute(0, x::sql::insertblob ::create(x::fdinputiter(x::fd::open("memo.txt", O_RDONLY)), x::fdinputiter());
x::sql::insertblob
passes a blob parameter to
execute
().
It's a reference-counted object whose
create
() takes a pair
of iterators for a sequence that defines the contents of a blob. The
resulting
x::sql::insertblob
can be used in place
of any parameter to execute
().
The iterators must iterate over char
s or
unsigned char
s. This is an indicator to the
database driver whether the blob contains character or binary data.
The semantics of character and binary blobs are driver-dependent.
auto fd=x::fd::open("blob.txt", O_RDONLY); int memo_id; std::pair<x::sql::insertblob, x::sql::bitflag> memo_blob=std::make_pair( x::sql::insertblob::create(x::fdinputiter(fd), x::fdinputiter()), 0); std::pair<x::sql::insertblob, x::sql::bitflag> memo_null_blob=std::make_pair( x::sql::insertblob::create(), 1); conn->execute("INSERT INTO memos(memo_id, memo_txt) VALUES (?, ?)", memo_id, memo_blob);
Similar to regular execute
() parameters,
a std::pair
of a
x::sql:insertblob
and
an x::sql::bitflag
specifies a possibly
NULL
value
for the parameter. Use create
() with no
parameters to create an x::sql:insertblob
for an empty character sequence,
and set the x::sql::bitflag
in order to specify
a NULL
value.
x::sql:insertblob
also works when it's passed
indirectly via a std::vector
to
execute
(), like any other parameter.
Database drivers may also support multiple blob parameters in a single
execute
().
Database drivers may also support blobs in
execute_vector
(), which uses
x::sql:insertblob
the same way as any
other parameter vector:
int upload_files(int first_id, const std::vector<std::string> &filenames) { std::vector<x::sql::bitflag> status; std::vector<int> ids; std::pair<std::vector<x::sql::insertblob> std::vector<x::sql::bitflag> memos; status.resize(filenames.size()); ids.reserve(filenames.size()); flags.first.reserve(filenames.size()); flags.second.reserve(filenames.size()); for (const auto &filename:filenames) { ids.push_back(first_id++); int isnull=filename.size() == 0; memos.second.push_back(isnull); memos.first.push_back(isnull ? x::insertblob::create(): x::insertblob::create(x::fd::inputiter(x::fd::open(filename, O_RDONLY)), x::fd::inputiter())); } conn->execute_vector("INSERT INTO memos(memo_id, memo_txt) VALUES (?, ?)", status, ids, memos); return first_id; }