virtual bool get_field(doid_t do_id, const Field* field, vector<uint8_t> &value) { // Get class from the objects table const Class* dcc = get_class(do_id); if(!dcc) { return false; // Object does not exist } bool stored = is_storable(dcc->get_id()); if(!stored) { return false; // Class has no database fields } FieldList fields; fields.push_back(field); FieldValues values; get_fields_from_table(do_id, dcc, fields, values); auto val_it = values.find(field); if(val_it == values.end()) { return false; } value = val_it->second; return true; }
virtual bool set_fields_if_empty(doid_t do_id, FieldValues &values) { // Get class from the objects table const Class* dcc = get_class(do_id); if(!dcc) { values.clear(); return false; // Object does not exist } bool stored = is_storable(dcc->get_id()); 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) { const Field* field = it->first; if(field->has_keyword("db")) { m_sql << "SELECT " << field->get_name() << " FROM fields_" << dcc->get_name() << " WHERE object_id=" << do_id << ";", into(value, ind); if(ind != i_null) { bool parse_err; failed = true; string packed_data = parse_value(field->get_type(), value, parse_err); if(parse_err) { m_log->error() << "Failed parsing value for field '" << field->get_name() << "' of object " << do_id << "' from database.\n"; continue; } values[field] = vector<uint8_t>(packed_data.begin(), packed_data.end()); continue; } value = format_value(it->first->get_type(), it->second); 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 soci_error &e) { m_sql.rollback(); // Revert transaction values.clear(); return false; } return true; }
bool DBOperation::verify_fields(const dclass::Class *dclass, const FieldValues& fields) { bool valid = true; for(auto it = fields.begin(); it != fields.end(); ++it) { if(!dclass->get_field_by_id(it->first->get_id())) { m_dbserver->m_log->warning() << "Field " << it->first->get_name() << " does not belong to object " << m_doid << "(" << dclass->get_name() << ")\n"; valid = false; } } return valid; }
void set_fields_in_table(doid_t id, const Class* dcc, const FieldValues &fields) { string name, value; for(auto it = fields.begin(); it != fields.end(); ++it) { if(it->first->has_keyword("db")) { name = it->first->get_name(); value = format_value(it->first->get_type(), it->second); m_sql << "UPDATE fields_" << dcc->get_name() << " SET " << name << "='" << value << "' WHERE object_id=" << id << ";"; } } }
void DBOperation::announce_fields(const FieldValues& fields) { // Calculate the fields that we are sending in our response: FieldValues changed_fields; FieldSet deleted_fields; for(auto it = fields.begin(); it != fields.end(); ++it) { if(it->second.empty()) deleted_fields.insert(it->first); else changed_fields[it->first] = it->second; } // Send delete fields broadcast if(!deleted_fields.empty()) { bool multi = (deleted_fields.size() > 1); DatagramPtr update = Datagram::create(); update->add_server_header(database_to_object(m_doid), m_sender, multi ? DBSERVER_OBJECT_DELETE_FIELDS : DBSERVER_OBJECT_DELETE_FIELD); update->add_doid(m_doid); if(multi) { update->add_uint16(deleted_fields.size()); } for(auto it = deleted_fields.begin(); it != deleted_fields.end(); ++it) { update->add_uint16((*it)->get_id()); } m_dbserver->route_datagram(update); } // Send update fields broadcast if(!changed_fields.empty()) { bool multi = (changed_fields.size() > 1); DatagramPtr update = Datagram::create(); update->add_server_header(database_to_object(m_doid), m_sender, multi ? DBSERVER_OBJECT_SET_FIELDS : DBSERVER_OBJECT_SET_FIELD); update->add_doid(m_doid); if(multi) { update->add_uint16(changed_fields.size()); } for(auto it = changed_fields.begin(); it != changed_fields.end(); ++it) { update->add_uint16(it->first->get_id()); update->add_data(it->second); } m_dbserver->route_datagram(update); } }