Beispiel #1
0
		void check_class(uint16_t id, string name, unsigned long hash)
		{
			DCClass* dcc = g_dcf->get_class(id);
			if(name != dcc->get_name())
			{
				// TODO: Try and update the database instead of exiting
				m_log->fatal() << "Class name '" << dcc->get_name() << "' from DCFile does not match"
				               " name '" << name << "' in database, for dc_id " << id << endl;
				m_log->fatal() << "Database must be rebuilt." << endl;
				exit(1);
			}

			HashGenerator gen;
			dcc->generate_hash(gen);
			if(hash != gen.get_hash())
			{
				// TODO: Try and update the database instead of exiting
				m_log->fatal() << "Class hash '" << gen.get_hash() << "' from DCFile does not match"
				               " hash '" << hash << "' in database, for dc_id " << id << endl;
				m_log->fatal() << "Database must be rebuilt." << endl;
				exit(1);
			}

			// TODO: Check class_fields table exists

		}
Beispiel #2
0
		bool get_field(uint32_t do_id, const DCField* field, vector<uint8_t> &value)
		{
			// 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
			}

			vector<DCField*> fields;
			fields.push_back(const_cast<DCField*>(field));
			map<DCField*, vector<uint8_t> > values;

			get_fields_from_table(do_id, dcc, fields, values);

			auto val_it = values.find(const_cast<DCField*>(field));
			if(val_it == values.end())
			{
				return false;
			}

			value = val_it->second;

			return true;
		}
Beispiel #3
0
		void del_fields(uint32_t do_id, const vector<DCField*> &fields)
		{
			DCClass *dcc = get_class(do_id);
			bool storable = is_storable(dcc->get_number());

			if(storable)
			{
				del_fields_in_table(do_id, dcc, fields);
			}
		}
Beispiel #4
0
		void del_field(uint32_t do_id, DCField* field)
		{
			DCClass *dcc = get_class(do_id);
			bool storable = is_storable(dcc->get_number());

			if(storable)
			{
				vector<DCField*> fields;
				fields.push_back(field);
				del_fields_in_table(do_id, dcc, fields);
			}
		}
Beispiel #5
0
		bool set_field_if_equals(uint32_t do_id, DCField* field, const vector<uint8_t> &equal,
		                         vector<uint8_t> &value)
		{
			// 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
			}

			if(!field->is_db())
			{
				return false;
			}

			string val;
			indicator ind;
			m_sql << "SELECT " << field->get_name() << " FROM fields_" << dcc->get_name()
			      << " WHERE object_id=" << do_id << ";", into(val, ind);
			if(ind != i_ok)
			{
				value.clear();
				return false;
			}

			string packed_equal(equal.begin(), equal.end());
			string eql = field->format_data(packed_equal, false);
			if(val != eql)
			{
				val = field->parse_string(val);
				value = vector<uint8_t>(val.begin(), val.end());
				return false;
			}

			string packed_data(value.begin(), value.end());
			val = field->format_data(packed_data, false);
			m_sql << "UPDATE fields_" << dcc->get_name() << " SET " << field->get_name()
			      << "='" << val << "' WHERE object_id=" << do_id << ";";
			return true;
		}
Beispiel #6
0
		void set_fields(uint32_t do_id, const map<DCField*, vector<uint8_t> > &fields)
		{
			DCClass *dcc = get_class(do_id);
			bool storable = is_storable(dcc->get_number());

			if(storable)
			{
				try
				{
					m_sql.begin(); // Start transaction
					set_fields_in_table(do_id, dcc, fields);
					m_sql.commit(); // End transaction
				}
				catch(const exception &e)
				{
					m_sql.rollback(); // Revert transaction
				}
			}
		}
Beispiel #7
0
		bool get_fields(uint32_t do_id, const vector<DCField*> &fields,
		                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
			}

			get_fields_from_table(do_id, dcc, fields, values);

			return true;
		}
Beispiel #8
0
		bool get_object(uint32_t do_id, DatabaseObject& dbo)
		{
			m_log->trace() << "Getting object with id" << do_id << endl;

			// Get class from the objects table
			DCClass* dcc = get_class(do_id);
			if(!dcc)
			{
				return false; // Object does not exist
			}
			dbo.dc_id = dcc->get_number();

			bool stored = is_storable(dcc->get_number());
			if(stored)
			{
				get_all_from_table(do_id, dcc, dbo.fields);
			}

			return true;
		}
Beispiel #9
0
		void delete_object(uint32_t do_id)
		{
			bool storable = false;
			DCClass* dcc = get_class(do_id);
			if(dcc)
			{
				// Note: needs to be called outside the transaction so it doesn't prevent deletion
				//       of the object in the `objects` table
				storable = is_storable(dcc->get_number());
			}

			m_log->debug() << "Deleting object with id " << do_id << "..." << endl;
			m_sql << "DELETE FROM objects WHERE id=" << do_id;

			if(dcc && storable)
			{
				m_log->trace() << "... object has stored field, also deleted." << endl;
				m_sql << "DELETE FROM fields_" << dcc->get_name() << " WHERE object_id=:id;", use(do_id);
			}

			push_id(do_id);
		}
Beispiel #10
0
		void check_classes()
		{
			int dc_id;
			uint8_t storable;
			string dc_name;
			unsigned long dc_hash;

			// Prepare sql statements
			statement get_row_by_id = (m_sql.prepare << "SELECT hash, name FROM classes WHERE id=:id",
			                           into(dc_hash), into(dc_name), use(dc_id));
			statement insert_class = (m_sql.prepare << "INSERT INTO classes VALUES (:id,:hash,:name,:stored)",
			                          use(dc_id), use(dc_hash), use(dc_name), use(storable));

			// For each class, verify an entry exists and has the correct name and value
			for(dc_id = 0; dc_id < g_dcf->get_num_classes(); ++dc_id)
			{
				get_row_by_id.execute(true);
				if(m_sql.got_data())
				{
					check_class(dc_id, dc_name, dc_hash);
				}
				else
				{
					DCClass* dcc = g_dcf->get_class(dc_id);

					// Create fields table for the class
					storable = create_fields_table(dcc);

					// Create class row in classes table
					HashGenerator gen;
					dcc->generate_hash(gen);
					dc_hash = gen.get_hash();
					dc_name = dcc->get_name();
					insert_class.execute(true);
				}
			}
		}
Beispiel #11
0
		uint32_t create_object(const DatabaseObject& dbo)
		{
			string field_name;
			vector<uint8_t> field_value;
			DCClass *dcc = g_dcf->get_class(dbo.dc_id);
			bool storable = is_storable(dbo.dc_id);

			uint32_t do_id = pop_next_id();
			if(!do_id)
			{
				return 0;
			}

			try
			{
				m_sql.begin(); // Start transaction
				m_sql << "INSERT INTO objects VALUES (" << do_id << "," << dbo.dc_id << ");";

				if(storable)
				{
					// TODO: This would probably be a lot faster if it was all one statement.
					//       Go ahead and simplify to one statement if you see a good way to do so.
					m_sql << "INSERT INTO fields_" << dcc->get_name() << "(object_id)"
					      " VALUES(" << do_id << ");";
					set_fields_in_table(do_id, dcc, dbo.fields);
				}

				m_sql.commit(); // End transaction
			}
			catch(const exception &e)
			{
				m_sql.rollback(); // Revert transaction
				return 0;
			}

			return do_id;
		}
Beispiel #12
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;
			};
		}
Beispiel #13
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;
			}
		}
Beispiel #14
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;
			}
		}