check complete sql

This commit is contained in:
Maarten L. Hekkelman
2025-12-29 15:52:02 +01:00
parent 61965c2391
commit 71cd4958bd
2 changed files with 75 additions and 57 deletions

View File

@@ -393,7 +393,8 @@ class transaction final
transaction(const transaction &) = delete;
transaction &operator=(const transaction &) = delete;
result exec(const std::string &query);
result exec(std::string query);
result exec(std::string query, std::string &tail);
template<typename... Ts>
cql_iterator_proxy<Ts...> stream(const std::string &sql)
@@ -419,6 +420,9 @@ class connection final
friend class transaction;
/// \brief Return true if the string @a sql contains a complete statement.
bool statementIsComplete(const std::string &sql) const;
private:
struct connection_impl *m_impl;
};

View File

@@ -862,6 +862,11 @@ connection::~connection()
delete m_impl;
}
bool connection::statementIsComplete(const std::string &sql) const
{
return sqlite3_complete(sql.c_str()) == 1;
}
// --------------------------------------------------------------------
transaction::transaction(connection &conn)
@@ -927,7 +932,19 @@ void transaction::rollback()
}
}
result transaction::exec(const std::string &query)
result transaction::exec(std::string query)
{
trim(query);
for (;;)
{
auto r = exec(query, query);
if (query.empty())
return r;
}
}
result transaction::exec(std::string query, std::string &tail)
{
category cat;
@@ -935,72 +952,69 @@ result transaction::exec(const std::string &query)
try
{
std::string sql = query;
while (not sql.empty())
const char *tail_ptr = nullptr;
int rc = sqlite3_prepare_v2(m_conn.m_impl->m_sqlite_db, query.data(), query.length(),
&stmt, &tail_ptr);
auto used = tail_ptr - query.data();
auto sql = query.substr(0, used);
tail = trim_copy(query.substr(used));
if (rc != SQLITE_OK)
throw std::runtime_error(std::format("Error preparing statement: {}", sqlite3_errmsg(m_conn.m_impl->m_sqlite_db)));
category ncat((std::format("result{}", m_conn.m_impl->m_next_result_nr++)));
std::swap(cat, ncat);
// for (int i = 0; i < sqlite3_column_count(stmt); ++i)
// cat.add_item(sqlite3_column_name(stmt, i));
for (;;)
{
const char *tail = nullptr;
int rc = sqlite3_prepare_v2(m_conn.m_impl->m_sqlite_db, sql.data(), sql.length(),
&stmt, &tail);
auto used = tail - sql.data();
sql = sql.substr(used, sql.length() - used);
trim(sql);
if (rc != SQLITE_OK)
throw std::runtime_error(std::format("Error preparing statement: {}", sqlite3_errmsg(m_conn.m_impl->m_sqlite_db)));
category ncat((std::format("result{}", m_conn.m_impl->m_next_result_nr++)));
std::swap(cat, ncat);
// for (int i = 0; i < sqlite3_column_count(stmt); ++i)
// cat.add_item(sqlite3_column_name(stmt, i));
for (;;)
rc = sqlite3_step(stmt);
if (rc == SQLITE_ROW)
{
rc = sqlite3_step(stmt);
if (rc == SQLITE_ROW)
row_initializer data;
for (int i = 0; i < sqlite3_column_count(stmt); ++i)
{
row_initializer data;
for (int i = 0; i < sqlite3_column_count(stmt); ++i)
switch (sqlite3_column_type(stmt, i))
{
switch (sqlite3_column_type(stmt, i))
{
case SQLITE_INTEGER:
data.emplace_back(sqlite3_column_name(stmt, i), sqlite3_column_int64(stmt, i));
break;
case SQLITE_FLOAT:
data.emplace_back(sqlite3_column_name(stmt, i), sqlite3_column_double(stmt, i));
break;
case SQLITE_TEXT:
data.emplace_back(sqlite3_column_name(stmt, i), (const char *)sqlite3_column_text(stmt, i));
break;
case SQLITE_BLOB:
throw std::runtime_error("Unexpected: blob in result");
break;
case SQLITE_NULL:
// data.emplace_back(sqlite3_column_name(stmt, i), ".");
break;
}
case SQLITE_INTEGER:
data.emplace_back(sqlite3_column_name(stmt, i), sqlite3_column_int64(stmt, i));
break;
case SQLITE_FLOAT:
data.emplace_back(sqlite3_column_name(stmt, i), sqlite3_column_double(stmt, i));
break;
case SQLITE_TEXT:
data.emplace_back(sqlite3_column_name(stmt, i), (const char *)sqlite3_column_text(stmt, i));
break;
case SQLITE_BLOB:
throw std::runtime_error("Unexpected: blob in result");
break;
case SQLITE_NULL:
// data.emplace_back(sqlite3_column_name(stmt, i), ".");
break;
}
cat.emplace(std::move(data));
continue;
}
if (rc == SQLITE_BUSY)
throw std::runtime_error("Oops, busy?");
if (rc == SQLITE_DONE)
break;
if (rc == SQLITE_ERROR)
throw std::runtime_error(std::format("Error in sqlite: {}", sqlite3_errmsg(m_conn.m_impl->m_sqlite_db)));
throw std::runtime_error("Unknown result from step");
cat.emplace(std::move(data));
continue;
}
sqlite3_finalize(stmt);
if (rc == SQLITE_BUSY)
throw std::runtime_error("Oops, busy?");
if (rc == SQLITE_DONE)
break;
if (rc == SQLITE_ERROR)
throw std::runtime_error(std::format("Error in sqlite: {}", sqlite3_errmsg(m_conn.m_impl->m_sqlite_db)));
throw std::runtime_error("Unknown result from step");
}
return result(std::move(cat), query);
sqlite3_finalize(stmt);
return result(std::move(cat), sql);
}
catch (const std::exception &ex)
{