Related
Using the online documentation and the code in the sample repo, I've implemented PubSub for a single incoming and multiple outgoing. The pull PubSub is an ordering subscription (would much prefer an ordered and deliever once, but that doesn't seem allowed). I have dead letter configured for each PubSub. Repeatably, the code will stop pulling messages. Sometimes in 5 minutes, sometimes after a couple of days. This morning, there were 55k messages waiting to be pulled. No messages in the dead letter. Based on the website, I expected something from the then() handler in the subscription, but there is no error messages. Here is the relevant parts my code.
/* These are based on https://github.com/googleapis/google-cloud-cpp/blob/HEAD/google/cloud/pubsub/samples/samples.cc */
/* https://cloud.google.com/pubsub/docs/handling-failures#dead-letter_topic */
/* https://cloud.google.com/blog/products/application-development/running-cplusplus-apps-with-the-help-of-pubsub-and-gke */
/* https://cloud.google.com/pubsub/docs/samples/pubsub-subscriber-error-listener#code-sample */
#include <google/cloud/pubsub/publisher.h>
#include <google/cloud/storage/client.h>
#include <google/cloud/pubsub/subscriber.h>
#include <google/cloud/pubsub/subscription_admin_client.h>
#include <google/cloud/pubsub/topic_admin_client.h>
#include <nlohmann/json.hpp>
void createTopic(const std::string& topicId, const std::string& dlTopicId, google::cloud::pubsub::TopicAdminClient& client)
{
namespace pubsub = ::google::cloud::pubsub;
[](pubsub::TopicAdminClient client, std::string project_id, std::string topic_id, std::string dl_topic_id)
{
auto topic = client.CreateTopic(pubsub::TopicBuilder(pubsub::Topic(project_id, topic_id)));
// Note that kAlreadyExists is a possible error when the library retries.
if (topic.status().code() == google::cloud::StatusCode::kAlreadyExists)
{
;
}
else if (!topic)
{
throw std::runtime_error(topic.status().message());
}
else
{
LOGn << "The topic " << topic_id << " was successfully created: " << topic->DebugString();
}
auto dl_topic = client.CreateTopic(pubsub::TopicBuilder(pubsub::Topic(project_id, dl_topic_id)));
// Note that kAlreadyExists is a possible error when the library retries.
if (dl_topic.status().code() == google::cloud::StatusCode::kAlreadyExists)
{
;
}
else if (!dl_topic)
{
throw std::runtime_error(dl_topic.status().message());
}
else
{
LOGn << "The deadletter topic " << dl_topic_id << " was successfully created: " << dl_topic->DebugString();
}
}
(client, pubSubProjectId, topicId, dlTopicId);
}
void createOrderingSubscription(const std::string& topicId, const std::string& subscriptionId, const std::string& dlTopicId, const std::string& dlSubscriptionId, google::cloud::pubsub::SubscriptionAdminClient& client)
{
namespace pubsub = ::google::cloud::pubsub;
return [](pubsub::SubscriptionAdminClient client, std::string const& project_id, std::string const& topic_id, std::string const& subscription_id, std::string const& dl_topic_id, std::string const& dl_subscription_id)
{
static const constexpr int DEAD_LETTER_DELIVERY_ATTEMPTS = 5;
auto sub = client.CreateSubscription(
pubsub::Topic(project_id, std::move(topic_id)),
pubsub::Subscription(project_id, subscription_id),
pubsub::SubscriptionBuilder{}
.enable_message_ordering(true)
.set_ack_deadline(std::chrono::seconds(60))
.set_dead_letter_policy(
pubsub::SubscriptionBuilder::MakeDeadLetterPolicy(
pubsub::Topic(project_id, dl_topic_id),
DEAD_LETTER_DELIVERY_ATTEMPTS))
);
if (sub.status().code() == google::cloud::StatusCode::kAlreadyExists)
{
;
}
else if (!sub)
{
throw std::runtime_error(sub.status().message());
}
else
{
LOGd << "The subscription " << subscription_id << " was successfully created: " << sub->DebugString();
}
auto dl_sub = client.CreateSubscription(
pubsub::Topic(project_id, std::move(dl_topic_id)),
pubsub::Subscription(project_id, dl_subscription_id)
);
if (dl_sub.status().code() == google::cloud::StatusCode::kAlreadyExists)
{
;
}
else if (! dl_sub)
{
throw std::runtime_error(sub.status().message());
}
else
{
LOGd << "The deadletter subscription " << dl_subscription_id << " was successfully created: " << dl_sub->DebugString();
}
return;
}
(client, pubSubProjectId, topicId, subscriptionId, dlTopicId, dlSubscriptionId);
}
void run()
{
while (running)
{
try
{
namespace pubsub = ::google::cloud::pubsub;;
int concurrency = 1;
pubsub::TopicAdminClient topicClient(pubsub::MakeTopicAdminConnection());
pubsub::SubscriptionAdminClient subscriptionClient(pubsub::MakeSubscriptionAdminConnection());
createTopicSubscriptionId(eId, fId, "", fTopicId, fSubscriptionId, fDLTopicId, fDLSubscriptionId);
createTopic(fTopicId, fDLTopicId, topicClient);
createOrderingSubscription(fTopicId, fSubscriptionId, fDLTopicId, fDLSubscriptionId, subscriptionClient);
fSubscriptionProblem = false;
auto const subscription = pubsub::Subscription(pubSubProjectId, fSubscriptionId);
auto subscriber = pubsub::Subscriber(pubsub::MakeSubscriberConnection(
subscription,
pubsub::SubscriberOptions{}
.set_max_outstanding_messages(concurrency)
.set_max_outstanding_bytes(concurrency * 1024)
.set_max_concurrency(concurrency),
pubsub::ConnectionOptions{}.set_background_thread_pool_size(concurrency))
);
auto session = subscriber.Subscribe([](pubsub::Message const& m, pubsub::AckHandler h) {
ProcessMsg::CommTopic topic = static_cast<ProcessMsg::CommTopic>(std::stoi(m.attributes()["topic"]));
bool g = true;
std::string msg = m.data();
LOGi << "Received message, id " << m.message_id() << ", attempt " << h.delivery_attempt() <<", ordering key '" << m.ordering_key() << "', topic " << ProcessMsg::commTopic(topic) << " (" << topic << ")";
messageCallback(msg);
std::move(h).ack();
})
.then([](::google::cloud::future<google::cloud::Status> f) {
LOGe << "Subscription problem : " << f.get();
fSubscriptionProblem = true;
});
if (! session.valid())
{
LOGe << "Subscribe session invalid";
break;
}
while (running && ! fSubscriptionProblem)
{
if (outgoingQueue.empty())
{
std::this_thread::sleep_for(std::chrono::milliseconds(500));
continue;
}
std::string gTopicId = "";
std::string gSubscriptionId = "";
std::string gDLTopicId = "";
std::string gDLSubscriptionId = "";
const OutgoingMsg omsg = outgoingQueue.front();
createTopicSubscriptionId(0, 0, omsg.identifier, gTopicId, gSubscriptionId, gDLTopicId, gDLSubscriptionId);
createTopic(gTopicId, gDLTopicId, topicClient);
createOrderingSubscription(gTopicId, gSubscriptionId, gDLTopicId, gDLSubscriptionId, subscriptionClient);
try
{
auto publisher = pubsub::Publisher(pubsub::MakePublisherConnection(pubsub::Topic(pubSubProjectId, gTopicId)));
auto id = publisher.Publish(pubsub::MessageBuilder{}
.SetData(omsg.msg)
.SetAttribute("timestamp", std::to_string(time(NULL)))
.Build()).get();
if (! id)
{
LOGe << "Failed to publish message " << id.status().message();
}
else
{
LOGd << "Published message, id : " << *id << " (" << omsg.msg << ") to " << pubSubProjectId << "/" << gTopicId;
outgoingQueue.pop_front();
}
}
catch (std::exception const& e)
{
LOGe << "Failed to publish message " << e.what();
}
}
if (running)
{
LOGn << "GCP problem, cancelling session";
session.cancel();
LOGd << "Waiting 15 seconds";
std::this_thread::sleep_for(std::chrono::seconds(15));
}
}
catch (std::runtime_error &e)
{
LOGe << "RuntimeError exception : " << e.what();
}
catch(std::exception& e)
{
LOGe << "Exception : " << e.what();
}
}
}
I was unlucky enough that his exact code was actually working for me. There is obviously some underlying problem that I am not seeing/understanding because it no longer works.
This is what is happening:
I am streaming data from a file, and when using the
buffer >> table_data;
As I output table_data each time, it is starting from the middle of the buffer.
The tricky thing, If I output the buffer using
std::cout << buffer.str();
That yields the correct data. So the stream buffer, has all of the right things, its just not going into table_data correctly.
See full code block below.
//read from table
buffer << table.rdbuf();
buffer.clear();
//clear table contents for rewrite later
table.clear();
std::ofstream table(filename);
while (buffer >> table_data)
{
temp_vec.push_back(table_data);
//num_table_items = 3, which is correct.
for (int i = 1; i < num_table_items; i++)
{
buffer >> table_data;
temp_vec.push_back(table_data);
}
//I removed the part where I write to the table from the vector because the problem is above.
temp_vec.clear();
}
if it matters, this is what the buffer is reading from the file:
1 'Gizmo' 19.99
2 'PowerGizmo' 29.99
3 'SingleTouch' 149.99
4 'MultiTouch' 199.99
5 'SuperGizmo' 49.99
And thats what is printed when I do the std::cout << buffer.str();
however, if I print table data after both "buffer >> table_data" lines in the code, i get this (same results if I print the vector):
Gizmo' 29.99 3
'SingleTouch' 149.99 4
'MultiTouch' 199.99 5
'SuperGizmo' 49.99 49.99
See how it starts in the middle? 'Gizmo' is even missing its first apostrophe. Any idea what is happening? Am i missing something obvious?
**EDIT: Here is more code as requested. This is the if statement that eventually calls the function, the entire function, and the function declaration from my Table class. Thank you everyone for the help.
//Function definiton
void update_table(std::string table_name, std::string table_path, std::string set_schema, std::string set_item,
std::string where_schema, std::string where_item);
//From file that calls the function
if (text == "DELETE" || text == "Delete" || text == "delete")
{
//skips "from"
std::cin >> objName >> objName >> text;
if (objName.back() == ';')
{
objName = objName.substr(0, objName.size()-1);
}
if (text == "WHERE" || text == "Where" || text == "where")
{
std::cin >> del_name >> operation >> del_param;
if (del_param.back() == ';')
{
del_param = del_param.substr(0, del_param.size()-1);
}
table.delete_table_data(objName, use_DB, del_name, operation, del_param);
}
}
//The entire function
void Table::update_table(std::string table_name, std::string table_path, std::string set_schema, std::string set_item,
std::string where_schema, std::string where_item)
{
chdir(table_path.c_str());
filename = table_name + ".txt";
std::ifstream table (filename);
//init counter
if (table)
{
getline(table, table_data);
table_info.str(table_data);
table_info.clear();
buffer << table.rdbuf();
buffer.clear();
buffer.str();
table.clear();
//Unneccessary?
table.close();
std::ofstream table(filename);
//Finds size of table, writes table labels back to file.
num_table_items = 0;
modify_count = 0;
while(table_info >> item_name)
{
table_info >> item_type;
table << item_name << " " << item_type << "\t\t";
if (item_name == set_schema) // && item_name == where_schema
{
set_index = num_table_items;
}
if (item_name == where_schema)
{
where_index = num_table_items;
}
num_table_items++;
}
std::cout << buffer.str() << std::endl;
while (getline(buffer, table_data))
{
std::cout << table_data << std::endl;
temp_vec.push_back(table_data);
for (int i = 1; i < num_table_items; i++)
{
buffer >> table_data;
std::cout << "i = " << i << " Data = " << table_data << std::endl;
temp_vec.push_back(table_data);
}
if (temp_vec[where_index] == where_item)
{
modify_count++;
temp_vec[set_index] = set_item;
}
//store in vector
for (int i = 0; i < temp_vec.size(); i++)
{
table_vec.push_back(temp_vec[i]);
std::cout << temp_vec[i] << " ";
}
temp_vec.clear();
}
for (int i = 0; i < table_vec.size(); i++)
{
if (i % num_table_items == 0)
{
table << "\n" << table_vec[i] << "\t";
}
else if (i % num_table_items == num_table_items - 1)
{
table << table_vec[i];
}
else
{
table << table_vec[i] << "\t\t";
}
if (table_vec[i].length() < 8 && i % num_table_items != num_table_items - 1)
{
table << "\t";
}
}
table.close();
table_vec.clear();
table_info.clear();
table_info.str();
//write vector to file.
if (modify_count == 1)
{
std::cout << "-- " << modify_count << " record modified." << std::endl;
}
else
{
std::cout << "-- " << modify_count << " records modified." << std::endl;
}
}
else
{
std:: cout << "-- !Failed to query " << table_name << " because it does not exist" << std::endl;
}
}
the user input that should invoke this is:
update Product
set name = 'Gizmo'
where name = 'SuperGizmo';
or
update Product set price = 14.99 where name = 'Gizmo';
My Sqlite connector works just fine the first time I try to insert rows, but after it is closed and I run the program again it won't work at all.
Here is my constructor
Sqldatabase::Sqldatabase() {
open_connection("Database.db");
sqlite3_stmt *statement;
std::string sql = "SELECT id FROM articles ORDER BY id DESC LIMIT 1";
char *query = &sql[0];
if(sqlite3_prepare_v2(db, query, -1, &statement, 0) == SQLITE_OK && sqlite3_step(statement) == SQLITE_ROW) {
article_counter = sqlite3_column_int(statement, 0) + 1;
} else {
article_counter = 1;
}
}
Here is my preparedStatement method.
bool Sqldatabase::prepareStatement(std::string sql) {
char *query = &sql[0];
sqlite3_stmt *statement;
int result;
if (sqlite3_prepare_v2(db, query, sql.size(), &statement, 0) == SQLITE_OK) {
result = sqlite3_step(statement);
std::cout << sql << '\n';
sqlite3_finalize(statement);
if(result == SQLITE_DONE) {
return true;
}
}
std::cout << "SQL failed: " << sql << '\n';
return false;
}
And finally here is where I call the method.
bool Sqldatabase::create_ART(int ng_id, std::string title, std::string author, std::string text) {
//Creating article
std::ostringstream s;
s << "INSERT INTO articles (id, title, author, content, created) " <<
"VALUES (" << article_counter << ", '" << title << "', '" << author << "', '" << text << "' , CURRENT_DATE)";
std::string sql(s.str());
prepareStatement(sql);
//Adding article to newsgroup
std::ostringstream t;
t << "INSERT INTO contains VALUES ( " << article_counter << " , " << ng_id << ")";
std::string sql2(t.str());
article_counter++;
return prepareStatement(sql2);
}
My test script looks like this. And I already have a Newsgroup with id 1 in the database.
Sqldatabase db;
int main(int argc, char* argv[]){
std::cout << "-----Test of Memdatabase, Newsgroup and Article classes-----" << std::endl;
db = Sqldatabase();
db.create_ART(1, "Happy day", "John", "Sunday afternoon is pretty chill");
db.create_ART(1, "Chill day", "Peter", "Sunday afternoon is pretty chill");
}
Ah, you're trying to create a new record with the same id. ids are typically unique. try:
db.create_ART(2, "Chill day", "Peter", "Sunday afternoon is pretty chill");
I want to read value from the user and use it in my select query. How can I use a dynamic value in the SQL query?
My current code gives me this error:
ORA-01002: fetch out of sequence
This is my code:
void buildQuery()
{
cout << "Enter flight no :";
cin >> value;
strcpy((char *)sql_statement.arr,"select fname from flights where
flno = " + value );
cout << "Query is " << (char *) sql_statement.arr<< endl;
}
void executeQuery()
{
sql_statement.len = strlen((char *) sql_statement.arr);
exec sql PREPARE S1 FROM :sql_statement;
exec sql declare C1 cursor FOR S1;
exec sql open C1 ;
while(1)
{
exec sql FETCH C1 INTO :fname;
if ( sqlca.sqlcode != 0)
{
cout << "past fetch..." <<endl;
break;
}
cout << "Employee Name is: = " << (char *)ename.arr << endl;
}
exec sql close C1;
}
I'm relatively new programming c++. I'm implementing a tree like index for a db using unorderd_map on the implementation of the tree data structure to store the children nodes. As im working with tree like structures the construction an search methods are recursive, also i store the pointers of the nodes, so i suspect i may have a sort of not well handled memory issue. I'm getting a segmentation fault. Next is my code and the output of it.
#include <memory>
#include <sstream>
#include <unordered_map>
#include <iostream>
#include <string>
#include <sqlite3.h>
#include "aux_functions.cpp"
#include <math.h>
using namespace std;
class TreeLikeIndex
{
public:
TreeLikeIndex(string attribute, string indices, int indices_count, short int is_leaf, unordered_map<string, TreeLikeIndex*> children);
TreeLikeIndex(string indices, int indices_count);
TreeLikeIndex();
string search(unordered_map<string, string> *);
private:
string indices;
int indices_count;
short int is_leaf;
string attribute;
unordered_map<string, TreeLikeIndex*> children;
};
string TreeLikeIndex::search(unordered_map<string, string> * _tuple)
{
if((*_tuple).empty() || this->is_leaf ) return this->indices;
string att_val = (*_tuple)[this->attribute];
(*_tuple).erase(this->attribute);
TreeLikeIndex * child_with_that_value = this->children[att_val];
return (*child_with_that_value).search(_tuple);
}
class DecisionTreeLikeIndexer
{
public:
DecisionTreeLikeIndexer(string, string, string);
int rebuild_index();
TreeLikeIndex * get_index();
private:
TreeLikeIndex * build_index(unordered_set<string> attributes_list, int depth, string comma_separated_ids, int ids_list_count);
TreeLikeIndex * index;
string source_db_address;
string dest_folder_address;
time_t time_of_last_build;
unordered_set<string> columns_names;
string source_table_name;
unordered_set<string> temp_tables_names;
string id_column_name;
sqlite3 * source_db_connection;
int table_count;
};
int DecisionTreeLikeIndexer::rebuild_index()
{
this->index = this->build_index(this->columns_names, 0, "", 0);
this->time_of_last_build = time(NULL);
return 0;
}
TreeLikeIndex * DecisionTreeLikeIndexer::get_index()
{
return this->index;
}
DecisionTreeLikeIndexer::DecisionTreeLikeIndexer(string source_db_address, string table_name, string dest_folder_address)
{
this->source_db_address = source_db_address;
this->dest_folder_address = dest_folder_address;
this->columns_names = Aux::get_column_names(source_db_address, table_name);
this->source_table_name = table_name;
this->id_column_name = "rowid";
this->source_db_connection = Aux::get_db_connection(this->source_db_address);
// Getting count of this table
sqlite3_stmt* statement;
string query = "SELECT count(*) FROM " + this->source_table_name + ";";
if(sqlite3_prepare(this->source_db_connection, query.c_str(), -1, &statement, 0) == SQLITE_OK)
{
int res = sqlite3_step(statement);
const unsigned char * count_char = sqlite3_column_text(statement,0);
if(res == SQLITE_ROW)
{
stringstream _temp;
_temp << count_char;
_temp >> this->table_count;
}
sqlite3_finalize(statement);
}
else
{
cout << "Error initializating Indexer (Getting initial table count): " << sqlite3_errmsg(this->source_db_connection) << endl;
}
}
TreeLikeIndex * DecisionTreeLikeIndexer::build_index(unordered_set<string> attributes_list, int depth, string comma_separated_ids, int ids_list_count)
{
if( attributes_list.size() <=1 || (depth > 0 && ids_list_count <= 1))
{
Aux::tabs(depth);
cout << "Leaf at depth: " << depth << " Ids are: " << comma_separated_ids << " Ids count: " << ids_list_count << endl;
static TreeLikeIndex * node = new TreeLikeIndex((string)comma_separated_ids, (int)ids_list_count);
return node;
}
string source_table = this->source_table_name;
int count = this->table_count;
if(depth > 0)
{
while(1)
{
source_table = *Aux::get_random_list_of_strings(1).begin();
if(this->temp_tables_names.insert(source_table).second) break;
}
const string create_temp_table_stmnt = "CREATE TEMP TABLE " + source_table + " AS SELECT * FROM " + this->source_table_name + " WHERE " + this->id_column_name + " IN(" + comma_separated_ids + ")";
sqlite3_exec(this->source_db_connection, create_temp_table_stmnt.c_str(),Aux::sqlt_callback,0,NULL);
count = ids_list_count;
Aux::tabs(depth);
cout << "Not root node" << endl;
}
Aux::tabs(depth);
cout << "Source table is: " << source_table << " Table count is: " << count << endl;
Aux::tabs(depth);
cout << "Attributes list is: "; for_each(attributes_list.begin(), attributes_list.end(),[](string v){cout << v << " ";});
cout << endl;
const double E = log2(count) ;
Aux::tabs(depth);
cout << "Entropy of node: " << E << endl;
string best_attribute;
double best_gain;
unordered_set<string> best_attribute_values;
for(string attr: attributes_list)
{
Aux::tabs(depth+1);
cout << "Analysing attribute: " << attr << endl;
const string get_at_count_values_query = "SELECT " + attr + ", count(" + attr + ") FROM " + source_table + " GROUP BY " + attr + ";";
sqlite3_stmt * stmnt;
double weighted_entropy = 0;
unordered_set<string> this_att_values;
if(sqlite3_prepare(this->source_db_connection, get_at_count_values_query.c_str(), -1, &stmnt, 0) == SQLITE_OK)
{
for(;;)
{
int res = sqlite3_step(stmnt);
if(res == SQLITE_DONE || res==SQLITE_ERROR)
{
double gAti = E - weighted_entropy;
Aux::tabs(depth+1);
cout << "Finish computing WE for att: " << attr << " Gain is: " << gAti << endl;
if(gAti > best_gain)
{
Aux::tabs(depth+1);
cout << "Found attribute with better gain." << endl;
best_gain = gAti;
best_attribute = attr;
best_attribute_values.clear();
Aux::tabs(depth+1);
for(string v:this_att_values)
{
best_attribute_values.insert(v);
}
cout << endl;
this_att_values.clear();
}
sqlite3_finalize(stmnt);
//delete &res;
break;
}
if(res == SQLITE_ROW)
{
string val = std::string(reinterpret_cast<const char*>(sqlite3_column_text(stmnt,0)));
int vSize = sqlite3_column_int(stmnt,1);
Aux::tabs(depth+2);
this_att_values.insert(val);
double ratio = double(vSize) / double(count);
weighted_entropy += double(ratio) * double(log2(vSize));
Aux::tabs(depth+2);
cout << "Processing value: " << val << " With vSize: " << vSize << " Current WE is: " << weighted_entropy << endl;
}
}
}
}
Aux::tabs(depth);
cout << "Finish processing attributes list. Best attribute is: " << best_attribute << " Best gain is: " << best_gain << endl;
Aux::tabs(depth);
cout << "Best attribute values are: "; for_each(best_attribute_values.begin(), best_attribute_values.end(), [](string v){cout << v << ",";}); cout << endl;
unordered_map<string, TreeLikeIndex *> children;
for(string val: best_attribute_values)
{
const string get_ids_of_bestatt_val = "SELECT rowid FROM " + source_table + " WHERE " + best_attribute + " = " + val + ";";
int ids_count = 0;
sqlite3_stmt * stmnt;
string ids = "";
bool first = 1;
int next_depth = depth + 1;
unordered_set<string> next_attributes_set;
for(string attr: attributes_list) if(attr != best_attribute) next_attributes_set.insert(attr);
if(sqlite3_prepare(this->source_db_connection, get_ids_of_bestatt_val.c_str(), -1, &stmnt,0) == SQLITE_OK)
{
for(;;)
{
int res = sqlite3_step(stmnt);
if(res == SQLITE_ROW)
{
string id = std::string(reinterpret_cast<const char*>(sqlite3_column_text(stmnt,0)));
if(!first) ids += "," + id;
else ids += id;
ids_count++;
}
if(res == SQLITE_DONE || res == SQLITE_ERROR)
{
Aux::tabs(depth+1);
cout << "Adding branch for val: " << val << endl;
Aux::tabs(depth+1);
cout << " Next attributes are: "; for_each(next_attributes_set.begin(), next_attributes_set.end(), [](string v){cout << v << ",";});
cout << " Depth is: " << next_depth << " Ids are: " << ids << " Ids count: " << ids_count << endl;
sqlite3_finalize(stmnt);
static TreeLikeIndex * temp_child = this->build_index(next_attributes_set, next_depth, ids, ids_count);
pair<string, TreeLikeIndex*> child (val, temp_child);
children.insert(child);
}
}
}
}
Aux::tabs(depth);
cout << "Finish processing node, will return." << endl;
static TreeLikeIndex * no_leaf_node = new TreeLikeIndex(best_attribute, "all", count, 0, children);
return no_leaf_node;
}
}
TreeLikeIndex::TreeLikeIndex(std::string attribute, std::string indices, int indices_count, short int is_leaf, unordered_map<std::string, TreeLikeIndex*> children)
{
this->attribute = attribute;
this->indices = indices;
this->is_leaf = is_leaf;
this->children = children;
this->children.clear();
for(pair<string, TreeLikeIndex*> p: children) this->children.insert(p);
this->indices_count = indices_count;
}
TreeLikeIndex::TreeLikeIndex(string indices, int indices_count)
{
this->indices = indices;
this->indices_count = indices_count;
this->is_leaf = 1;
}
TreeLikeIndex::TreeLikeIndex()
{
this->indices = "";
this->indices_count = 0;
this->is_leaf = 1;
}
int main()
{
string source_db_address = "my_table";
string table_name = "b";
string dest_folder_address = ".";
DecisionTreeLikeIndexer indexer(source_db_address, table_name, dest_folder_address);
indexer.rebuild_index();
}
And the output is:
Source table is: b Table count is: 9
Attributes list is: cant_n_dec cant_n_des cant_n_control
Entropy of node: 3.16993
Analysing attribute: cant_n_dec
Processing value: 1 With vSize: 1 Current WE is: 0
Processing value: 2 With vSize: 4 Current WE is: 0.888889
Processing value: 3 With vSize: 2 Current WE is: 1.11111
Processing value: 4 With vSize: 1 Current WE is: 1.11111
Processing value: 5 With vSize: 1 Current WE is: 1.11111
Finish computing WE for att: cant_n_dec Gain is: 2.05881
Found attribute with better gain.
Analysing attribute: cant_n_des
Processing value: 1 With vSize: 2 Current WE is: 0.222222
Processing value: 2 With vSize: 4 Current WE is: 1.11111
Processing value: 3 With vSize: 2 Current WE is: 1.33333
Processing value: 5 With vSize: 1 Current WE is: 1.33333
Finish computing WE for att: cant_n_des Gain is: 1.83659
Analysing attribute: cant_n_control
Processing value: 1 With vSize: 2 Current WE is: 0.222222
Processing value: 2 With vSize: 3 Current WE is: 0.750543
Processing value: 3 With vSize: 3 Current WE is: 1.27886
Processing value: 5 With vSize: 1 Current WE is: 1.27886
Finish computing WE for att: cant_n_control Gain is: 1.89106
Finish processing attributes list. Best attribute is: cant_n_dec Best gain is: 2.05881
Best attribute values are: 1,2,3,4,5,
Adding branch for val: 1
Next attributes are: cant_n_control,cant_n_des, Depth is: 1 Ids are: 3 Ids count: 1
Leaf at depth: 1 Ids are: 3 Ids count: 1
Segmentation fault
I'm not shure but....
I think the problem can be in the following cycle
for(;;)
{
int res = sqlite3_step(stmnt);
if(res == SQLITE_ROW)
{
string id = std::string(reinterpret_cast<const char*>(sqlite3_column_text(stmnt,0)));
if(!first) ids += "," + id;
else ids += id;
ids_count++;
}
if(res == SQLITE_DONE || res == SQLITE_ERROR)
{
Aux::tabs(depth+1);
cout << "Adding branch for val: " << val << endl;
Aux::tabs(depth+1);
cout << " Next attributes are: "; for_each(next_attributes_set.begin(), next_attributes_set.end(), [](string v){cout << v << ",";});
cout << " Depth is: " << next_depth << " Ids are: " << ids << " Ids count: " << ids_count << endl;
sqlite3_finalize(stmnt);
static TreeLikeIndex * temp_child = this->build_index(next_attributes_set, next_depth, ids, ids_count);
pair<string, TreeLikeIndex*> child (val, temp_child);
children.insert(child);
}
}
I don't understand when terminate (no exit conditions in the for(;;), no return's and no break's in the block).
And I suspect that che segmentation fault is caused by the following instruction
int res = sqlite3_step(stmnt);
when, after the SQLITE_DONE or SQLITE_ERROR case (whith a call to
sqlite3_finalize(stmnt);
), the cycle is iterated again, with a stmnt invalid.
The following can be a solution?
if ( sqlite3_prepare(this->source_db_connection, get_ids_of_bestatt_val.c_str(), -1, &stmnt,0) == SQLITE_OK)
{
while ( sqlite3_step(stmnt) == SQLITE_ROW )
{
ids += ( first ? "" : "," )
+ std::string(reinterpret_cast<const char*>(sqlite3_column_text(stmnt,0)));
ids_count++;
}
Aux::tabs(depth+1);
cout << "Adding branch for val: " << val << endl;
Aux::tabs(depth+1);
cout << " Next attributes are: ";
for_each(next_attributes_set.begin(), next_attributes_set.end(), [](string v){cout << v << ",";});
cout << " Depth is: " << next_depth << " Ids are: " << ids << " Ids count: " << ids_count << endl;
sqlite3_finalize(stmnt);
static TreeLikeIndex * temp_child = this->build_index(next_attributes_set, next_depth, ids, ids_count);
pair<string, TreeLikeIndex*> child (val, temp_child);
children.insert(child);
}