Здравствуйте, PM, Вы писали:
PM>Здравствуйте, Gorilla, Вы писали:
G>>А можно добавить use биндеры для char* и wchar_t* ?
PM>Добавил пару перегруженных функций: PM>
Вопрос: какова область видимости блоба получаемого через into? Нужно ли как-то освобождать память под него?
Например:
sqlitepp::session db("test.db");
sqlitepp::blob icon;
db << "SELECT data FROM incons WHERE id=1234", sqlitepp::into(icon);
// можно ли обращаться к icon.data? нужно ли освобождать память?
Далее: у меня есть класс производный от std:vector<unsigned char>, но into и use биндеры не принимают его напрямую, требуется некрасивое приведение типов. Можно ли заставить биндеры принимать любые производные вектора?
Еще одно пожелание: когда я отправляю селект через << на sqlitepp::session, мне часто требуется писать if (!db.last_exec()) throw std::runtime_error("no data selected"). Может можно сделать какую-нибудь опцию при открытии базы, или сделать какой-нибудь модификатор вроде db << "sql query", sqlitepp::throw(), или метод db.set_throw_if_no_data(true) который включает выбрасывание исключения если запрос имел into биндеры и не вернул никаких данных. Даже не знаю как лучше.
В добавок одно наблюдения от меня, которое сэкономит вам кучу времени и нервных клеток. Функция sqlite3_enable_shared_cache делает работу с БД потоконебезопасной!!! Shared caсhe у них баговый и может вызывать отказ при обработке параллельных запросов. В документации про это ничего не сказано, остерегайтесь использования этой функции.
Здравствуйте, Gorilla, Вы писали:
G>Вопрос: какова область видимости блоба получаемого через into? Нужно ли как-то освобождать память под него?
The pointers returned are valid until a type conversion occurs as described above, or until sqlite3_step() or sqlite3_reset() or sqlite3_finalize() is called. The memory space used to hold strings and BLOBs is freed automatically. Do not pass the pointers returned sqlite3_column_blob(), sqlite3_column_text(), etc. into sqlite3_free().
G>// можно ли обращаться к icon.data? нужно ли освобождать память?
Нельзя, не нужно. Чтобы обратиться к полученным данным, нужно либо подержать объект sqlitepp::statement до момента обращения к данным, либо писать свой конвертер, чтобы управлять памятью по-своему.
G>Далее: у меня есть класс производный от std:vector<unsigned char>, но into и use биндеры не принимают его напрямую, требуется некрасивое приведение типов. Можно ли заставить биндеры принимать любые производные вектора?
Напишите конвертер с красивым приведением
Может ли запрос дождаться освобождения базы, а не вылетать с SQLITE_BUSY? Есть ли у sqlite встроенные средства для этого или надо организовывать самописную синхронизацию?
Тем более, что база может использоваться из разных приложений, к примеру.
Здравствуйте, ntp, Вы писали:
ntp>Здравствуйте, Gorilla, Вы писали:
G>>Вопрос: какова область видимости блоба получаемого через into? Нужно ли как-то освобождать память под него?
ntp>
The pointers returned are valid until a type conversion occurs as described above, or until sqlite3_step() or sqlite3_reset() or sqlite3_finalize() is called. The memory space used to hold strings and BLOBs is freed automatically. Do not pass the pointers returned sqlite3_column_blob(), sqlite3_column_text(), etc. into sqlite3_free().
G>>// можно ли обращаться к icon.data? нужно ли освобождать память? ntp>Нельзя, не нужно. Чтобы обратиться к полученным данным, нужно либо подержать объект sqlitepp::statement до момента обращения к данным, либо писать свой конвертер, чтобы управлять памятью по-своему.
Я так и предполагал, но на всякий случай спрашиваю, вдруг там statement живет до следующего запроса. Пофиг, буду грузить в вектор.
G>>Далее: у меня есть класс производный от std:vector<unsigned char>, но into и use биндеры не принимают его напрямую, требуется некрасивое приведение типов. Можно ли заставить биндеры принимать любые производные вектора? ntp>Напишите конвертер с красивым приведением
К сожалению я не настолько продвинут в с++ чтобы лезть в такие дебри.
ntp>Может ли запрос дождаться освобождения базы, а не вылетать с SQLITE_BUSY? Есть ли у sqlite встроенные средства для этого или надо организовывать самописную синхронизацию? ntp>Тем более, что база может использоваться из разных приложений, к примеру.
sqlite3_busy_timeout(database->impl(), 10*1000); — устанавливаем таймаут 10сек.
Здравствуйте, Gorilla, Вы писали:
G>>>Далее: у меня есть класс производный от std:vector<unsigned char>, но into и use биндеры не принимают его напрямую, требуется некрасивое приведение типов. Можно ли заставить биндеры принимать любые производные вектора? ntp>>Напишите конвертер с красивым приведением G>К сожалению я не настолько продвинут в с++ чтобы лезть в такие дебри.
Если нельзя привести ваш класс к базовому (и уже его передать в into/use), то тогда вот пример, в который можно подставить любой объект, лишь бы его данные, захваченные blob'ом, можно было описать непрерывным куском памяти:
Здравствуйте, ntp, Вы писали:
ntp>Если нельзя привести ваш класс к базовому (и уже его передать в into/use)
Можно привести, я сейчас так и делаю. Но это некрасиво, хотелось бы избавиться от длинного приведения, чтобы оно делалось автоматом в конвертере, и чтобы работало для любого класса производного от vector. Такое возможно?
Здравствуйте, Gorilla, Вы писали:
G>Здравствуйте, ntp, Вы писали:
ntp>>Если нельзя привести ваш класс к базовому (и уже его передать в into/use) G>Можно привести, я сейчас так и делаю. Но это некрасиво, хотелось бы избавиться от длинного приведения, чтобы оно делалось автоматом в конвертере, и чтобы работало для любого класса производного от vector. Такое возможно?
Если я правильно понял суть вопроса, то можно выкрутиться так:
#include <boost/type_traits/is_base_of.hpp>
#include <boost/utility/enable_if.hpp>
// Конвертер для классов унаследованных от std::vector<T>. Тип VectorT должен обеспечить конструктор из диапазона итераторов:
//
// template<typename T>
// struct VectorT : public std::vector<T>
// {
// /// Конструктор из диапазона итераторов, в частном случае это может быть [value_type const* begin, value_type const* end)
// template<typename ForwardIterator>
// VectorT(ForwardIterator begin, ForwardIterator end) : std::vector<T>(begin, end) {}
// };
//template<typename VectorT>
struct converter<VectorT,
typename boost::enable_if<boost::is_base_of<std::vector<typename VectorT::value_type>, VectorT> >::type>
{
typedef blob base_type;
static VectorT to(blob const& b)
{
typename VectorT::value_type const* f = reinterpret_cast<typename VectorT::value_type const*>(b.data);
typename VectorT::value_type const* l = f + b.size / sizeof(typename VectorT::value_type);
return VectorT(f, l);
}
static blob from(VectorT const& t)
{
blob b;
b.data = t.empty()? 0 : &t[0];
b.size = t.size() * sizeof(typename VectorT::value_type);
return b;
}
};
И тогда такое будет работать:
template<typename T>
struct my_vector : public std::vector<T>
{
my_vector() {}
template<typename ForwardIt>
my_vector(ForwardIt begin, ForwardIt end)
: std::vector<T>(begin, end)
{
}
};
void test()
{
my_vector<int> data, data2;
data.push_back(1);
data.push_back(11);
using namespace sqlitepp;
session se("test.db");
se << utf(L"create table my_vector(val blob)");
se << utf(L"insert into my_vector(val) values(:val)"), use(data);
se << utf(L"select val from my_vector"), into(data2);
ensure("my_vector", data2 == data);
}
PM>Если я правильно понял суть вопроса, то можно выкрутиться так:
А можно то-же самое, но без boost? Одна из причин по которой я выбрал sqlitepp — это отсутствие зависимостей от boost.
Здравствуйте, Gorilla, Вы писали:
G>А можно то-же самое, но без boost? Одна из причин по которой я выбрал sqlitepp — это отсутствие зависимостей от boost.
В С++11 есть std::is_base_of и std::enable_if
Можно реализовать их самому, либо посмотреть как сделано в Boost и реализовать самому.
Здравствуйте, PM, Вы писали:
PM>Здравствуйте, Gorilla, Вы писали:
G>>А можно то-же самое, но без boost? Одна из причин по которой я выбрал sqlitepp — это отсутствие зависимостей от boost.
PM>В С++11 есть std::is_base_of и std::enable_if
Тогда хорошо бы было добавить в проект соответствующий конвертор, поместив его внутри блока #if _MSC_VER >= 1600 / #endif
Кстати, в последней версии из svn возникает такой варнинг при компиляции:
cl : Command line warning D9030: '/Gm' is incompatible with multiprocessing; ignoring /MP switch
И еще хорошо бы было обновить sqlite до версии 3.7.12.
Здравствуйте, Gorilla, Вы писали:
PM>>В С++11 есть std::is_base_of и std::enable_if G>Тогда хорошо бы было добавить в проект соответствующий конвертор, поместив его внутри блока #if _MSC_VER >= 1600 / #endif
Не вижу в этом большой потребности, т.к. поддержка С++11 — отдельная тема. Вообще, поддержка наследников std::vector в конвертере данных это достаточно экзотический случай. Если вам необходимы конвертеры для собственных типов, сделайте в своем проекте специализацию sqlitepp::converter<> для них.
G>Кстати, в последней версии из svn возникает такой варнинг при компиляции: G>
G>cl : Command line warning D9030: '/Gm' is incompatible with multiprocessing; ignoring /MP switch
G>
G>И еще хорошо бы было обновить sqlite до версии 3.7.12.
Предупржедение починил, обновлять SQLite пока некогда.
Вопрос к PM: не планируется ли портировать библиотеку под mysql? Несмотря на все ухищрения мой проект перерос sqlite, требуется взрослая база данных. Но я так привык к sqlite++, что другие обертки кажутся ужасными.
Здравствуйте, Gorilla, Вы писали:
G>Вопрос к PM: не планируется ли портировать библиотеку под mysql? Несмотря на все ухищрения мой проект перерос sqlite, требуется взрослая база данных. Но я так привык к sqlite++, что другие обертки кажутся ужасными.
Довольно странно в качестве примера взрослой базы данных приводить mysql. А у Postgres’а есть вполне modern C++-style обёртка libpqxx.
Здравствуйте, Gorilla, Вы писали:
G>Вопрос к PM: не планируется ли портировать библиотеку под mysql? Несмотря на все ухищрения мой проект перерос sqlite, требуется взрослая база данных. Но я так привык к sqlite++, что другие обертки кажутся ужасными.
Нет, я не планирую добавлять в SQlite++ поддержку других БД. По-моему, нет необъодимости в еще одной универсальной БД библиотеке
На вскидку могу вспомнить SOCI и CppDB (последнюю кстати я успешно использовал в одном проекте c MySQL)