Skip to content

Commit

Permalink
Improve API to take into account sqlite pragma for column introspection
Browse files Browse the repository at this point in the history
  • Loading branch information
Sildra committed Sep 19, 2023
1 parent 924d990 commit 4569bea
Show file tree
Hide file tree
Showing 8 changed files with 96 additions and 8 deletions.
2 changes: 1 addition & 1 deletion docs/utilities.md
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ Similarly, to get the description of all columns in the given table:

```cpp
soci::column_info ci;
soci::statement st = (sql.prepare_column_descriptions(table_name), into(ci));
soci::statement st = sql.prepare_column_descriptions(table_name, ci);

st.execute();
while (st.fetch())
Expand Down
5 changes: 4 additions & 1 deletion include/soci/session.h
Original file line number Diff line number Diff line change
Expand Up @@ -138,13 +138,16 @@ class SOCI_DECL session
// it makes sense to bind std::string for the output field.
details::prepare_temp_type prepare_table_names();

[[deprecated("Use the overload prepare_column_descriptions with column_info to support more backends (i.e. sqlite)")]]
details::prepare_temp_type prepare_column_descriptions(std::string & table_name);

// Returns prepare_temp_type for the internally composed query
// for the list of column descriptions.
// Since this is intended for use with statement objects, where results are obtained one row after another,
// it makes sense to bind either std::string for each output field or soci::column_info for the whole row.
// Note: table_name is a non-const reference to prevent temporary objects,
// this argument is bound as a regular "use" element.
details::prepare_temp_type prepare_column_descriptions(std::string & table_name);
details::prepare_temp_type prepare_column_descriptions(std::string & table_name, soci::column_info & info);

// Functions for basic portable DDL statements.

Expand Down
6 changes: 6 additions & 0 deletions include/soci/soci-backend.h
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,12 @@ class session_backend
" where table_schema = 'public' and table_name = :t";
}

virtual details::prepare_temp_type prepare_column_descriptions_statement(
details::prepare_type& prepare, std::string & table_name, soci::column_info& info) const
{
return prepare << get_column_descriptions_query(), soci::use(table_name, "t"), soci::into(info);
}

virtual std::string create_table(const std::string & tableName)
{
return "create table " + tableName + " (";
Expand Down
6 changes: 6 additions & 0 deletions include/soci/sqlite3/soci-sqlite3.h
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,12 @@ struct sqlite3_session_backend : details::session_backend
return "select name as \"TABLE_NAME\""
" from sqlite_master where type = 'table'";
}
std::string get_column_descriptions_query() const override
{
return "pragma table_info(:t)";
}
details::prepare_temp_type prepare_column_descriptions_statement(
details::prepare_type& prepare, std::string & table_name, soci::column_info& info) override;
std::string create_column_type(data_type dt,
int , int ) override
{
Expand Down
66 changes: 66 additions & 0 deletions src/backends/sqlite3/session.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,64 @@ using namespace sqlite_api;

namespace // anonymous
{
namespace soci
{
// Overload of the column_info to work with the specific table structure of sqlite
struct sqlite_column_info final : public column_info { sqlite_column_info() = delete; }

template<>
struct type_conversion<sqlite_column_info>
{
typedef values base_type;
static void from_base(values const & v, indicator /* ind */, sqlite_column_info & ci)
{
ci.name = v.get<std::string>("name");
ci.length = 0;
ci.precision = 0;
ci.scale = 0;
ci.nullable = (v.get<std::string>("notnull") == "0");

std::string type_name = v.get<std::string>("type");
std::transform(type_name.begin(), type_name.end(), type_name.begin(), ::tolower);

if (type_name == "text" || type_name == "clob" ||
type_name.find("char") != std::string::npos)
{
ci.type = dt_string;
}
else if (type_name.find("int") != std::string::npos ||
type_name.find("number") != std::string::npos ||
type_name.find("numeric") != std::string::npos)
{
ci.type = dt_integer;
}
else if (type_name.find("double") != std::string::npos ||
type_name.find("float") != std::string::npos ||
type_name.find("real") != std::string::npos)
{
ci.type = dt_double;
}
else if (type_name.find("time") != std::string::npos ||
type_name.find("date") != std::string::npos)
{
ci.type = dt_date;
}
else if (type_name.find("blob") != std::string::npos ||
type_name.find("oid") != std::string::npos)
{
ci.type = dt_blob;
}
else if (type_name.find("xml") != std::string::npos)
{
ci.type = dt_xml;
}
else
{
ci.type = dt_string;
}
}
}
} // !namesapce soci

// Callback function use to construct the error message in the provided stream.
//
Expand Down Expand Up @@ -328,3 +386,11 @@ sqlite3_blob_backend * sqlite3_session_backend::make_blob_backend()
{
return new sqlite3_blob_backend(*this);
}

details::prepare_temp_type prepare_column_descriptions_statement(
details::prepare_type& prepare, std::string & table_name, soci::column_info& info)
{
soci::sqlite_column_info& sqlite_info = reinterpret_cast<soci::sqlite_column_info&>(info);
return prepare << get_column_descriptions_query(), soci::use(table_name, "t"), soci::into(info);

}
7 changes: 7 additions & 0 deletions src/core/session.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -471,6 +471,13 @@ details::prepare_temp_type session::prepare_column_descriptions(std::string & ta
return prepare << backEnd_->get_column_descriptions_query(), use(table_name, "t");
}

details::prepare_temp_type session::prepare_column_descriptions(std::string & table_name, soci::column_info & info)
{
ensureConnected(backEnd_);

return backEnd_->prepare_column_descriptions_statement(table_name, info);
}

ddl_type session::create_table(const std::string & tableName)
{
ddl_type ddl(*this);
Expand Down
6 changes: 3 additions & 3 deletions tests/oracle/test-oracle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1116,7 +1116,7 @@ TEST_CASE("Oracle DDL with metadata", "[oracle][ddl]")
bool j_found = false;
bool other_found = false;
soci::column_info ci;
soci::statement st1 = (sql.prepare_column_descriptions(ddl_t1), into(ci));
soci::statement st1 = sql.prepare_column_descriptions(ddl_t1, ci);
st1.execute();
while (st1.fetch())
{
Expand Down Expand Up @@ -1194,7 +1194,7 @@ TEST_CASE("Oracle DDL with metadata", "[oracle][ddl]")
bool k_found = false;
bool big_found = false;
other_found = false;
soci::statement st3 = (sql.prepare_column_descriptions(ddl_t1), into(ci));
soci::statement st3 = sql.prepare_column_descriptions(ddl_t1, ci);
st3.execute();
while (st3.fetch())
{
Expand Down Expand Up @@ -1235,7 +1235,7 @@ TEST_CASE("Oracle DDL with metadata", "[oracle][ddl]")
k_found = false;
bool m_found = false;
other_found = false;
soci::statement st4 = (sql.prepare_column_descriptions(ddl_t2), into(ci));
soci::statement st4 = sql.prepare_column_descriptions(ddl_t2, ci);
st4.execute();
while (st4.fetch())
{
Expand Down
6 changes: 3 additions & 3 deletions tests/postgresql/test-postgresql.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -774,7 +774,7 @@ TEST_CASE("PostgreSQL DDL with metadata", "[postgresql][ddl]")
bool j_found = false;
bool other_found = false;
soci::column_info ci;
soci::statement st1 = (sql.prepare_column_descriptions(ddl_t1), into(ci));
soci::statement st1 = sql.prepare_column_descriptions(ddl_t1, ci);
st1.execute();
while (st1.fetch())
{
Expand Down Expand Up @@ -852,7 +852,7 @@ TEST_CASE("PostgreSQL DDL with metadata", "[postgresql][ddl]")
bool k_found = false;
bool big_found = false;
other_found = false;
soci::statement st3 = (sql.prepare_column_descriptions(ddl_t1), into(ci));
soci::statement st3 = sql.prepare_column_descriptions(ddl_t1, ci);
st3.execute();
while (st3.fetch())
{
Expand Down Expand Up @@ -893,7 +893,7 @@ TEST_CASE("PostgreSQL DDL with metadata", "[postgresql][ddl]")
k_found = false;
bool m_found = false;
other_found = false;
soci::statement st4 = (sql.prepare_column_descriptions(ddl_t2), into(ci));
soci::statement st4 = sql.prepare_column_descriptions(ddl_t2, ci);
st4.execute();
while (st4.fetch())
{
Expand Down

0 comments on commit 4569bea

Please sign in to comment.