Exemplo n.º 1
0
		// 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;
		}
Exemplo n.º 2
0
bool unpack_db_fields(DatagramIterator &dgi, DCClass* dclass,
                      std::unordered_map<DCField*, std::vector<uint8_t> > &required,
                      std::map<DCField*, std::vector<uint8_t> > &ram)
{
	// Unload ram and required fields from database resp
	uint16_t db_field_count = dgi.read_uint16();
	for(uint16_t i = 0; i < db_field_count; ++i)
	{
		uint16_t field_id = dgi.read_uint16();
		DCField *field = dclass->get_field_by_index(field_id);
		if(!field)
		{
			return false;
		}
		if(field->is_ram())
		{
			dgi.unpack_field(field, ram[field]);
		}
		else if(field->is_required())
		{
			dgi.unpack_field(field, required[field]);
		}
		else
		{
			dgi.skip_field(field);
		}
	}

	return true;
}
Exemplo n.º 3
0
		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 << ";";
				}
			}
		}
Exemplo n.º 4
0
		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());
					}
				}
			}
		}
Exemplo n.º 5
0
		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());
					}
				}
			}
		}
Exemplo n.º 6
0
		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;
			};
		}
Exemplo n.º 7
0
void DBStateServer::handle_datagram(Datagram &in_dg, DatagramIterator &dgi)
{
	channel_t sender = dgi.read_uint64();
	uint16_t msgtype = dgi.read_uint16();
	switch(msgtype)
	{
		case DBSS_OBJECT_ACTIVATE_WITH_DEFAULTS:
		{
			handle_activate(dgi, false);
			break;
		}
		case DBSS_OBJECT_ACTIVATE_WITH_DEFAULTS_OTHER:
		{
			handle_activate(dgi, true);
			break;
		}
		case DBSS_OBJECT_DELETE_DISK:
		{
			uint32_t do_id = dgi.read_uint32();

			// If object exists broadcast the delete message
			auto obj_keyval = m_objs.find(do_id);
			if(obj_keyval != m_objs.end())
			{
				DistributedObject* obj = obj_keyval->second;
				std::set<channel_t> targets;

				// Add location to broadcast
				if(obj->get_location())
				{
					targets.insert(obj->get_location());
				}

				// Add AI to broadcast
				if(obj->get_ai())
				{
					targets.insert(obj->get_ai());
				}

				// Add owner to broadcast
				if(obj->get_owner())
				{
					targets.insert(obj->get_owner());
				}

				// Build and send datagram
				Datagram dg(targets, sender, DBSS_OBJECT_DELETE_DISK);
				dg.add_uint32(do_id);
				send(dg);
			}

			// Send delete to database
			Datagram dg(m_db_channel, do_id, DBSERVER_OBJECT_DELETE);
			dg.add_uint32(do_id);
			send(dg);

			break;
		}
		case STATESERVER_OBJECT_SET_FIELD:
		{
			uint32_t do_id = dgi.read_uint32();
			uint32_t field_id = dgi.read_uint16();

			DCField* field = g_dcf->get_field_by_index(field_id);
			if(field && field->is_db())
			{
				m_log->trace() << "Forwarding SetField for field with id " << field_id
				              << ", on object " << do_id << " to database." << std::endl;

				Datagram dg(m_db_channel, do_id, DBSERVER_OBJECT_SET_FIELD);
				dg.add_uint32(do_id);
				dg.add_uint16(field_id);
				dg.add_data(dgi.read_remainder());
				send(dg);
			}
			break;
		}
		case STATESERVER_OBJECT_SET_FIELDS:
		{
			uint32_t do_id = dgi.read_uint32();
			uint16_t field_count = dgi.read_uint16();

			std::unordered_map<DCField*, std::vector<uint8_t> > db_fields;
			for(uint16_t i = 0; i < field_count; ++i)
			{
				uint16_t field_id = dgi.read_uint16();
				DCField* field = g_dcf->get_field_by_index(field_id);
				if(!field)
				{
					m_log->warning() << "Received invalid field in SetFields"
					                 " with id " << field_id << std::endl;
					break;
				}
				if(field->is_db())
				{
					dgi.unpack_field(field, db_fields[field]);
				}
			}

			if(db_fields.size() > 0)
			{
				m_log->trace() << "Forwarding SetFields on object " << do_id << " to database." << std::endl;

				Datagram dg(m_db_channel, do_id, DBSERVER_OBJECT_SET_FIELDS);
				dg.add_uint32(do_id);
				dg.add_uint16(field_count);
				for(auto it = db_fields.begin(); it != db_fields.end(); ++it)
				{
					dg.add_uint16(it->first->get_number());
					dg.add_data(it->second);
				}
				send(dg);
			}

			break;
		}
		case STATESERVER_OBJECT_GET_FIELD:
		{
			uint32_t r_context = dgi.read_uint32();
			uint32_t r_do_id = dgi.read_uint32();
			uint16_t field_id = dgi.read_uint16();

			// If object is active or loading, the Object or Loader will handle it
			if(m_objs.find(r_do_id) != m_objs.end() ||
			        m_loading.find(r_do_id) != m_loading.end())
			{
				break;
			}

			m_log->trace() << "Received GetField for field with id " << field_id
			              << " on inactive object with id " << r_do_id << std::endl;

			// Check field is "ram db" or "required"
			DCField* field = g_dcf->get_field_by_index(field_id);
			if(!field || !(field->is_required() ||
			               (field->is_ram() && field->is_db())))
			{
				Datagram dg(sender, r_do_id, STATESERVER_OBJECT_GET_FIELD_RESP);
				dg.add_uint32(r_context);
				dg.add_uint8(false);
				send(dg);
			}

			if(field->is_db())
			{
				// Get context for db query
				uint32_t db_context = m_next_context++;

				// Prepare reponse datagram
				if(m_context_datagrams.find(db_context) == m_context_datagrams.end())
				{
					m_context_datagrams[db_context].add_server_header(sender, r_do_id,
					        STATESERVER_OBJECT_GET_FIELD_RESP);
				}

				m_context_datagrams[db_context].add_uint32(r_context);

				// Send query to database
				Datagram dg(m_db_channel, r_do_id, DBSERVER_OBJECT_GET_FIELD);
				dg.add_uint32(db_context);
				dg.add_uint32(r_do_id);
				dg.add_uint16(field_id);
				send(dg);
			}
			else // Field is required and not-db
			{
				Datagram dg = Datagram(sender, r_do_id, STATESERVER_OBJECT_GET_FIELD_RESP);
				dg.add_uint32(r_context);
				dg.add_uint8(true);
				dg.add_uint16(field_id);
				dg.add_data(field->get_default_value());
				send(dg);
			}

			break;
		}
		case DBSERVER_OBJECT_GET_FIELD_RESP:
		{
			uint32_t db_context = dgi.read_uint32();

			// Check context
			auto dg_keyval = m_context_datagrams.find(db_context);
			if(dg_keyval == m_context_datagrams.end())
			{
				break; // Not meant for me, handled by LoadingObject
			}

			m_log->trace() << "Received GetFieldResp from database." << std::endl;

			// Get the datagram from the db_context
			Datagram dg(dg_keyval->second);

			// Cleanup the context
			m_context_datagrams.erase(db_context);

			// Check to make sure the datagram is appropriate
			DatagramIterator check_dgi = DatagramIterator(dg);
			uint16_t resp_type = check_dgi.get_msg_type();
			if(resp_type != STATESERVER_OBJECT_GET_FIELD_RESP)
			{
				if(resp_type == STATESERVER_OBJECT_GET_FIELDS_RESP)
				{
					m_log->warning() << "Received GetFieldsResp, but expecting GetFieldResp." << std::endl;
				}
				else if(resp_type == STATESERVER_OBJECT_GET_ALL_RESP)
				{
					m_log->warning() << "Received GetAllResp, but expecting GetFieldResp." << std::endl;
				}
				break;
			}

			// Add database field payload to response (don't know dclass, so must copy payload) and send
			dg.add_data(dgi.read_remainder());
			send(dg);

			break;
		}
		case STATESERVER_OBJECT_GET_FIELDS:
		{
			uint32_t r_context = dgi.read_uint32();
			uint32_t r_do_id = dgi.read_uint32();
			uint16_t field_count = dgi.read_uint16();

			// If object is active or loading, the Object or Loader will handle it
			if(m_objs.find(r_do_id) != m_objs.end() ||
			        m_loading.find(r_do_id) != m_loading.end())
			{
				break;
			}

			m_log->trace() << "Received GetFields for inactive object with id " << r_do_id << std::endl;

			// Read requested fields from datagram
			std::list<DCField*> db_fields; // Ram|required db fields in request
			std::list<DCField*> ram_fields; // Ram|required but not-db fields in request
			for(uint16_t i = 0; i < field_count; ++i)
			{
				uint16_t field_id = dgi.read_uint16();
				DCField* field = g_dcf->get_field_by_index(field_id);
				if(!field)
				{
					Datagram dg(sender, r_do_id, STATESERVER_OBJECT_GET_FIELDS_RESP);
					dg.add_uint32(r_context);
					dg.add_uint8(false);
					send(dg);
				}
				else if(field->is_ram() || field->is_required())
				{
					if(field->is_db())
					{
						db_fields.push_back(field);
					}
					else
					{
						ram_fields.push_back(field);
					}
				}
			}

			if(db_fields.size())
			{
				// Get context for db query
				uint32_t db_context = m_next_context++;

				// Prepare reponse datagram
				if(m_context_datagrams.find(db_context) == m_context_datagrams.end())
				{
					m_context_datagrams[db_context].add_server_header(sender, r_do_id,
					        STATESERVER_OBJECT_GET_FIELDS_RESP);
				}
				m_context_datagrams[db_context].add_uint32(r_context);
				m_context_datagrams[db_context].add_uint8(true);
				m_context_datagrams[db_context].add_uint16(ram_fields.size() + db_fields.size());
				for(auto it = ram_fields.begin(); it != ram_fields.end(); ++it)
				{
					m_context_datagrams[db_context].add_uint16((*it)->get_number());
					m_context_datagrams[db_context].add_data((*it)->get_default_value());
				}

				// Send query to database
				Datagram dg(m_db_channel, r_do_id, DBSERVER_OBJECT_GET_FIELDS);
				dg.add_uint32(db_context);
				dg.add_uint32(r_do_id);
				dg.add_uint16(db_fields.size());
				for(auto it = db_fields.begin(); it != db_fields.end(); ++it)
				{
					dg.add_uint16((*it)->get_number());
				}
				send(dg);
			}
			else // If no database fields exist
			{
				Datagram dg = Datagram(sender, r_do_id, STATESERVER_OBJECT_GET_FIELDS_RESP);
				dg.add_uint32(r_context);
				dg.add_uint8(true);
				dg.add_uint16(ram_fields.size());
				for(auto it = ram_fields.begin(); it != ram_fields.end(); ++it)
				{
					dg.add_uint16((*it)->get_number());
					dg.add_data((*it)->get_default_value());
				}
				send(dg);
			}

			break;
		}
		case DBSERVER_OBJECT_GET_FIELDS_RESP:
		{
			uint32_t db_context = dgi.read_uint32();

			// Check context
			auto dg_keyval = m_context_datagrams.find(db_context);
			if(dg_keyval == m_context_datagrams.end())
			{
				break; // Not meant for me, handled by LoadingObject
			}

			// Get the datagram from the db_context
			Datagram dg(dg_keyval->second);

			// Cleanup the context
			m_context_datagrams.erase(db_context);

			// Check to make sure the datagram is appropriate
			DatagramIterator check_dgi = DatagramIterator(dg);
			uint16_t resp_type = check_dgi.get_msg_type();
			if(resp_type != STATESERVER_OBJECT_GET_FIELDS_RESP)
			{
				if(resp_type == STATESERVER_OBJECT_GET_FIELD_RESP)
				{
					m_log->warning() << "Received GetFieldResp, but expecting GetFieldsResp." << std::endl;
				}
				else if(resp_type == STATESERVER_OBJECT_GET_ALL_RESP)
				{
					m_log->warning() << "Received GetAllResp, but expecting GetFieldsResp." << std::endl;
				}
				break;
			}

			m_log->trace() << "Received GetFieldResp from database." << std::endl;

			// Add database field payload to response (don't know dclass, so must copy payload).
			if(dgi.read_uint8() == true)
			{
				dgi.read_uint16(); // Discard field count
				dg.add_data(dgi.read_remainder());
			}
			send(dg);

			break;
		}
		case STATESERVER_OBJECT_GET_ALL:
		{
			uint32_t r_context = dgi.read_uint32();
			uint32_t r_do_id = dgi.read_uint32();

			// If object is active or loading, the Object or Loader will handle it
			if(m_objs.find(r_do_id) != m_objs.end() ||
			        m_loading.find(r_do_id) != m_loading.end())
			{
				break;
			}

			m_log->trace() << "Received GetAll for inactive object with id " << r_do_id << std::endl;

			// Get context for db query, and remember caller with it
			uint32_t db_context = m_next_context++;

			if(m_context_datagrams.find(db_context) == m_context_datagrams.end())
			{
				m_context_datagrams[db_context].add_server_header(sender, r_do_id,
				        STATESERVER_OBJECT_GET_ALL_RESP);
			}

			m_context_datagrams[db_context].add_uint32(r_context);
			m_context_datagrams[db_context].add_uint32(r_do_id);
			m_context_datagrams[db_context].add_uint64(INVALID_CHANNEL); // Location

			// Cache the do_id --> context in case we get a dbss_activate
			m_inactive_loads[r_do_id].insert(r_context);

			// Send query to database
			Datagram dg(m_db_channel, r_do_id, DBSERVER_OBJECT_GET_ALL);
			dg.add_uint32(db_context);
			dg.add_uint32(r_do_id);
			send(dg);

			break;
		}
		case DBSERVER_OBJECT_GET_ALL_RESP:
		{
			uint32_t db_context = dgi.read_uint32();

			// Check context
			auto dg_keyval = m_context_datagrams.find(db_context);
			if(dg_keyval == m_context_datagrams.end())
			{
				break; // Not meant for me, handled by LoadingObject
			}

			// Get the datagram from the db_context
			Datagram dg(dg_keyval->second);

			// Cleanup the context
			m_context_datagrams.erase(db_context);

			// Check to make sure the datagram is appropriate
			DatagramIterator check_dgi = DatagramIterator(dg);
			uint16_t resp_type = check_dgi.get_msg_type();
			if(resp_type != STATESERVER_OBJECT_GET_ALL_RESP)
			{
				if(resp_type == STATESERVER_OBJECT_GET_FIELD_RESP)
				{
					m_log->warning() << "Received GetFieldResp, but expecting GetAllResp." << std::endl;
				}
				else if(resp_type == STATESERVER_OBJECT_GET_FIELDS_RESP)
				{
					m_log->warning() << "Received GetFieldsResp, but expecting GetAllResp." << std::endl;
				}
				break;
			}

			// Get do_id from datagram
			check_dgi.seek_payload();
			check_dgi.skip(8 + 4); // skip over sender and context to do_id;
			uint32_t do_id = check_dgi.read_uint32();

			// Remove cached loading operation
			if(m_inactive_loads[do_id].size() > 1)
			{
				m_inactive_loads[do_id].erase(db_context);
			}
			else
			{
				m_inactive_loads.erase(do_id);
			}

			m_log->trace() << "Received GetAllResp from database." << std::endl;

			// If object not found, just cleanup the context map
			if(dgi.read_uint8() != true)
			{
				break; // Object not found
			}

			// Read object class
			uint16_t dc_id = dgi.read_uint16();
			if(!dc_id)
			{
				m_log->error() << "Received object from database with unknown dclass"
				               << " - id:" << dc_id << std::endl;
				break;
			}
			DCClass* r_dclass = g_dcf->get_class(dc_id);

			// Get fields from database
			std::unordered_map<DCField*, std::vector<uint8_t> > required_fields;
			std::map<DCField*, std::vector<uint8_t> > ram_fields;
			if(!unpack_db_fields(dgi, r_dclass, required_fields, ram_fields))
			{
				m_log->error() << "Error while unpacking fields from database." << std::endl;
				break;
			}

			// Add class to response
			dg.add_uint16(r_dclass->get_number());

			// Add required fields to datagram
			int dcc_field_count = r_dclass->get_num_inherited_fields();
			for(int i = 0; i < dcc_field_count; ++i)
			{
				DCField *field = r_dclass->get_inherited_field(i);
				if(!field->as_molecular_field() && field->is_required())
				{
					auto req_it = required_fields.find(field);
					if(req_it != required_fields.end())
					{
						dg.add_data(req_it->second);
					}
					else
					{
						dg.add_data(field->get_default_value());
					}
				}
			}

			// Add ram fields to datagram
			dg.add_uint16(ram_fields.size());
			for(auto it = ram_fields.begin(); it != ram_fields.end(); ++it)
			{
				dg.add_uint16(it->first->get_number());
				dg.add_data(it->second);
			}

			// Send response back to caller
			send(dg);

			break;
		}
		default:
		{
			if(msgtype < STATESERVER_MSGTYPE_MIN || msgtype > DBSERVER_MSGTYPE_MAX)
			{
				m_log->warning() << "Received unknown message of type " << msgtype << std::endl;
			}
			else
			{
				m_log->trace() << "Ignoring stateserver or database message"
				              << " of type " << msgtype << std::endl;
			}
		}
	}
}
Exemplo n.º 8
0
		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;
			}
		}
Exemplo n.º 9
0
		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;
			}
		}