// returns true if class has db fields bool create_fields_table(DCClass* dcc) { stringstream ss; ss << "CREATE TABLE IF NOT EXISTS fields_" << dcc->get_name() << "(object_id INT NOT NULL PRIMARY KEY"; int db_field_count = 0; for(int i = 0; i < dcc->get_num_inherited_fields(); ++i) { DCField* field = dcc->get_inherited_field(i); if(field->is_db() && !field->as_molecular_field()) { db_field_count += 1; // TODO: Store SimpleParameters and fields with 1 SimpleParameter // as a simpler type. // NOTE: This might be a lot easier if the DCParser was modified // such that atomic fields containing only 1 DCSimpleParameter // element are initialized as a DCSimpleField subclass of DCAtomicField. // TODO: Also see if you can't find a convenient way to get the max length of // for example a string field, and use a VARCHAR(len) instead of TEXT. // Same for blobs with VARBINARY. ss << "," << field->get_name() << " TEXT"; } } if(db_field_count > 0) { ss << ");"; m_sql << ss.str(); return true; } return false; }
void del_fields_in_table(uint32_t id, DCClass* dcc, const vector<DCField*> &fields) { string name; for(auto it = fields.begin(); it != fields.end(); ++it) { DCField* field = *it; if(field->is_db()) { m_sql << "UPDATE fields_" << dcc->get_name() << " SET " << field->get_name() << "=NULL WHERE object_id=" << id << ";"; } } }
void get_all_from_table(uint32_t id, DCClass* dcc, map<DCField*, vector<uint8_t> > &fields) { string value; indicator ind; for(int i = 0; i < dcc->get_num_inherited_fields(); ++i) { DCField* field = dcc->get_inherited_field(i); if(field->is_db()) { m_sql << "SELECT " << field->get_name() << " FROM fields_" << dcc->get_name() << " WHERE object_id=" << id << ";", into(value, ind); if(ind == i_ok) { string packed_data = field->parse_string(value); fields[field] = vector<uint8_t>(packed_data.begin(), packed_data.end()); } } } }
void get_fields_from_table(uint32_t id, DCClass* dcc, const vector<DCField*> &fields, map<DCField*, vector<uint8_t> > &values) { string value; indicator ind; for(auto it = fields.begin(); it != fields.end(); ++it) { DCField* field = *it; if(field->is_db()) { m_sql << "SELECT " << field->get_name() << " FROM fields_" << dcc->get_name() << " WHERE object_id=" << id << ";", into(value, ind); if(ind == i_ok) { string packed_data = field->parse_string(value); values[field] = vector<uint8_t>(packed_data.begin(), packed_data.end()); } } } }
virtual void handle_datagram(Datagram &in_dg, DatagramIterator &dgi) { channel_t sender = dgi.read_uint64(); unsigned short msg_type = dgi.read_uint16(); switch(msg_type) { case DBSERVER_CREATE_STORED_OBJECT: { unsigned int context = dgi.read_uint32(); // Start response with generic header Datagram resp; resp.add_server_header(sender, m_control_channel, DBSERVER_CREATE_STORED_OBJECT_RESP); resp.add_uint32(context); // Get DistributedClass unsigned short dc_id = dgi.read_uint16(); DCClass *dcc = gDCF->get_class(dc_id); if(!dcc) { m_log->error() << "Invalid DCClass when creating object: #" << dc_id << std::endl; resp.add_uint32(0); send(resp); return; } // Unpack fields to be passed to database DatabaseObject dbo(dc_id); unsigned short field_count = dgi.read_uint16(); m_log->spam() << "Unpacking fields..." << std::endl; try { for(unsigned int i = 0; i < field_count; ++i) { unsigned short field_id = dgi.read_uint16(); DCField *field = dcc->get_field_by_index(field_id); if(field) { if(field->is_db()) { dgi.unpack_field(field, dbo.fields[field]); } else { std::string tmp; dgi.unpack_field(field, tmp); } } } } catch(std::exception &e) { m_log->error() << "Error while unpacking fields, msg may be truncated. e.what(): " << e.what() << std::endl; resp.add_uint32(0); send(resp); return; } // Check for required fields, and populate with defaults m_log->spam() << "Checking all required fields exist..." << std::endl; for(int i = 0; i < dcc->get_num_inherited_fields(); ++i) { DCField *field = dcc->get_inherited_field(i); if(field->is_required() && field->is_db() && !field->as_molecular_field()) { if(dbo.fields.find(field) == dbo.fields.end()) { if(!field->has_default_value()) { m_log->error() << "Field " << field->get_name() << " missing when trying to create " "object of type " << dcc->get_name(); resp.add_uint32(0); send(resp); return; } else { dbo.fields[field] = field->get_default_value(); } } } } // Create object in database m_log->spam() << "Creating stored object..." << std::endl; unsigned int do_id = m_db_engine->create_object(dbo); if(do_id == 0 || do_id < m_min_id || do_id > m_max_id) { m_log->error() << "Ran out of DistributedObject ids while creating new object." << std::endl; resp.add_uint32(0); send(resp); return; } m_log->spam() << "... created with ID: " << do_id << std::endl; resp.add_uint32(do_id); send(resp); } break; case DBSERVER_SELECT_STORED_OBJECT_ALL: { unsigned int context = dgi.read_uint32(); Datagram resp; resp.add_server_header(sender, m_control_channel, DBSERVER_SELECT_STORED_OBJECT_ALL_RESP); resp.add_uint32(context); unsigned int do_id = dgi.read_uint32(); DatabaseObject dbo; if(m_db_engine->get_object(do_id, dbo)) { resp.add_uint8(1); resp.add_uint16(dbo.dc_id); resp.add_uint16(dbo.fields.size()); for(auto it = dbo.fields.begin(); it != dbo.fields.end(); ++it) { resp.add_uint16(it->first->get_number()); resp.add_data(it->second); } } else { resp.add_uint8(0); } send(resp); } break; case DBSERVER_DELETE_STORED_OBJECT: { if(dgi.read_uint32() == DBSERVER_DELETE_STORED_OBJECT_VERIFY_CODE) { unsigned int do_id = dgi.read_uint32(); m_db_engine->delete_object(do_id); m_log->debug() << "Deleted object with ID: " << do_id << std::endl; } else { m_log->warning() << "Wrong delete verify code." << std::endl; } } break; default: m_log->error() << "Recieved unknown MsgType: " << msg_type << std::endl; }; }
bool set_fields_if_equals(uint32_t do_id, const map<DCField*, vector<uint8_t> > &equals, map<DCField*, vector<uint8_t> > &values) { // Get class from the objects table DCClass* dcc = get_class(do_id); if(!dcc) { return false; // Object does not exist } bool stored = is_storable(dcc->get_number()); if(!stored) { return false; // Class has no database fields } bool failed = false; string value; indicator ind; vector<DCField*> null_fields; try { m_sql.begin(); // Start transaction for(auto it = equals.begin(); it != equals.end(); ++it) { DCField* field = it->first; if(field->is_db()) { m_sql << "SELECT " << field->get_name() << " FROM fields_" << dcc->get_name() << " WHERE object_id=" << do_id << ";", into(value, ind); if(ind != i_ok) { null_fields.push_back(field); failed = true; continue; } string packed_equal(it->second.begin(), it->second.end()); string equal = field->format_data(packed_equal, false); if(value == equal) { string packed_data(values[field].begin(), values[field].end()); string insert = field->format_data(packed_data, false); m_sql << "UPDATE fields_" << dcc->get_name() << " SET " << field->get_name() << "='" << insert << "' WHERE object_id=" << do_id << ";"; \ } else { failed = true; } value = field->parse_string(value); values[field] = vector<uint8_t>(value.begin(), value.end()); } } if(failed) { for(auto it = null_fields.begin(); it != null_fields.end(); ++it) { values.erase(*it); } m_sql.rollback(); // Revert transaction return false; } else { m_sql.commit(); // End transaction return true; } } catch(const exception &e) { m_sql.rollback(); // Revert transaction values.clear(); return false; } }
bool set_fields_if_empty(uint32_t do_id, map<DCField*, vector<uint8_t> > &values) { // Get class from the objects table DCClass* dcc = get_class(do_id); if(!dcc) { values.clear(); return false; // Object does not exist } bool stored = is_storable(dcc->get_number()); if(!stored) { values.clear(); return false; // Class has no database fields } bool failed = false; string value; indicator ind; try { m_sql.begin(); // Start transaction for(auto it = values.begin(); it != values.end(); ++it) { DCField* field = it->first; if(field->is_db()) { m_sql << "SELECT " << field->get_name() << " FROM fields_" << dcc->get_name() << " WHERE object_id=" << do_id << ";", into(value, ind); if(ind != i_null) { failed = true; string packed_data = field->parse_string(value); values[field] = vector<uint8_t>(packed_data.begin(), packed_data.end()); continue; } string packed_data(it->second.begin(), it->second.end()); value = it->first->format_data(packed_data, false); m_sql << "UPDATE fields_" << dcc->get_name() << " SET " << field->get_name() << "='" << value << "' WHERE object_id=" << do_id << ";"; } } if(failed) { m_sql.rollback(); // Revert transaction } else { m_sql.commit(); // End transaction } } catch(const exception &e) { m_sql.rollback(); // Revert transaction values.clear(); return false; } }