diff --git a/legacyworlds-server-beans-system/src/main/java/com/deepclone/lw/beans/sys/ConstantsRegistrarBean.java b/legacyworlds-server-beans-system/src/main/java/com/deepclone/lw/beans/sys/ConstantsRegistrarBean.java
index 5a0cf11..414ba46 100644
--- a/legacyworlds-server-beans-system/src/main/java/com/deepclone/lw/beans/sys/ConstantsRegistrarBean.java
+++ b/legacyworlds-server-beans-system/src/main/java/com/deepclone/lw/beans/sys/ConstantsRegistrarBean.java
@@ -32,6 +32,8 @@ public class ConstantsRegistrarBean
 		// Misc. game-related values
 		cDesc = "Game updates - batch size.";
 		defs.add( new ConstantDefinition( "game.batchSize" , "Game (misc)" , cDesc , 20.0 , 1.0 , true ) );
+		cDesc = "Event processing - batch size.";
+		defs.add( new ConstantDefinition( "game.events.batchSize" , "Game (misc)" , cDesc , 100.0 , 1.0 , true ) );
 		cDesc = "Population growth factor.";
 		defs.add( new ConstantDefinition( "game.growthFactor" , "Game (misc)" , cDesc , 50.0 , 1.0 , true ) );
 		cDesc = "Increase to the population growth factor caused by reanimation centres.";
diff --git a/legacyworlds-server-data/db-structure/parts/020-extensions.sql b/legacyworlds-server-data/db-structure/parts/020-extensions.sql
index 9adc475..50db2a8 100644
--- a/legacyworlds-server-data/db-structure/parts/020-extensions.sql
+++ b/legacyworlds-server-data/db-structure/parts/020-extensions.sql
@@ -28,3 +28,8 @@ CREATE USER MAPPING FOR :dbuser
 	OPTIONS ( user :dbuser_string , password :dbupass );
 
 GRANT USAGE ON FOREIGN SERVER srv_logging TO :dbuser;
+
+/* The events sytem uses the hash store extension to convert events from the
+ * queues to main storage.
+ */
+CREATE EXTENSION hstore;
\ No newline at end of file
diff --git a/legacyworlds-server-data/db-structure/parts/030-data/170-events.sql b/legacyworlds-server-data/db-structure/parts/030-data/170-events.sql
index 36bd27f..356d9e2 100644
--- a/legacyworlds-server-data/db-structure/parts/030-data/170-events.sql
+++ b/legacyworlds-server-data/db-structure/parts/030-data/170-events.sql
@@ -239,6 +239,28 @@ CREATE SEQUENCE events.event_id_sequence;
 GRANT SELECT,UPDATE ON events.event_id_sequence TO :dbuser;
 
 
+/*
+ * Pending events
+ * --------------
+ *
+ * This table is updated when events are inserted into queues and when they
+ * are converted. It tracks events that need to be converted.
+ * 
+ * Note: the table does not have a primary key or foreign keys; it is simply
+ * 		a cache which must not get in the way of inserts into queues.
+ *
+ * Warning: a record in this table may be orphaned, i.e. there could be no
+ *		corresponding entry in the queue table.
+ */
+DROP TABLE IF EXISTS events.pending_events CASCADE;
+CREATE TABLE events.pending_events(
+	/* Event identifier */
+	event_id		BIGINT NOT NULL ,
+	/* Event type */
+	evdef_id		VARCHAR(48) NOT NULL
+);
+
+
 /*
  * Event storage table
  * -------------------
diff --git a/legacyworlds-server-data/db-structure/parts/040-functions/170-event-definitions.sql b/legacyworlds-server-data/db-structure/parts/040-functions/170-event-definitions.sql
index 564c971..f593da8 100644
--- a/legacyworlds-server-data/db-structure/parts/040-functions/170-event-definitions.sql
+++ b/legacyworlds-server-data/db-structure/parts/040-functions/170-event-definitions.sql
@@ -707,6 +707,33 @@ REVOKE EXECUTE
 	FROM PUBLIC;
 
 
+/*
+ * Trigger used to insert entries into pending_events
+ * --------------------------------------------------
+ * 
+ * This function is used as a trigger to insert queued events into the
+ * events.pending_events table.
+ * 
+ * Parameters:
+ *		TG_ARGV[0]	Event type identifier
+ */
+DROP FUNCTION IF EXISTS events.tgf_eq_insert( );
+CREATE FUNCTION events.tgf_eq_insert(  )
+		RETURNS TRIGGER
+		LANGUAGE PLPGSQL
+		STRICT VOLATILE SECURITY DEFINER
+	AS $tgf_eq_insert$
+BEGIN
+	INSERT INTO events.pending_events( event_id , evdef_id )
+		VALUES ( NEW.event_id , TG_ARGV[0] );
+	RETURN NEW;
+END;
+$tgf_eq_insert$;
+
+REVOKE EXECUTE
+	ON FUNCTION events.tgf_eq_insert( )
+	FROM PUBLIC;
+
 	
 /*
  * Create the event queuing table for a new definition
@@ -734,14 +761,14 @@ CREATE FUNCTION events.evdef_create_queue_table( _evdef_id TEXT )
 	AS $evdef_create_queue_table$
 
 DECLARE
+	_tsfx	TEXT;
 	_rec	RECORD;
 	_qstr	TEXT;
 	_fname	TEXT;
 
 BEGIN
-	
-	_qstr := 'CREATE TABLE events.eq_' || replace( _evdef_id , '-' , '_' )
-		|| $tbl_def$ (
+	_tsfx := replace( _evdef_id , '-' , '_' );
+	_qstr := 'CREATE TABLE events.eq_' || _tsfx || $tbl_def$ (
 			event_id BIGINT NOT NULL PRIMARY KEY
 					DEFAULT nextval('events.event_id_sequence'::regclass) ,
 			event_rtime TIMESTAMP WITHOUT TIME ZONE NOT NULL
@@ -782,9 +809,14 @@ BEGIN
 	_qstr := _qstr || ');';
 	EXECUTE _qstr;
 	
-	_qstr := 'GRANT INSERT ON TABLE events.eq_' || replace( _evdef_id , '-' , '_' )
+	_qstr := 'GRANT INSERT ON TABLE events.eq_' || _tsfx
 		|| ' TO $init_code$ || $1 || $init_code$;';
 	EXECUTE _qstr;
+	
+	_qstr := 'CREATE TRIGGER tg_eqi_' || _tsfx || ' AFTER INSERT ON events.eq_'
+		|| _tsfx || ' FOR EACH ROW EXECUTE PROCEDURE events.tgf_eq_insert('''
+		|| _evdef_id || ''');';
+	EXECUTE _qstr;
 END;
 $evdef_create_queue_table$; $init_code$ USING $1; END; $init_func$;
 SELECT _temp_init_func(:dbuser_string);
diff --git a/legacyworlds-server-data/db-structure/parts/040-functions/172-event-storage.sql b/legacyworlds-server-data/db-structure/parts/040-functions/172-event-storage.sql
new file mode 100644
index 0000000..ed351fa
--- /dev/null
+++ b/legacyworlds-server-data/db-structure/parts/040-functions/172-event-storage.sql
@@ -0,0 +1,183 @@
+-- LegacyWorlds Beta 6
+-- PostgreSQL database scripts
+--
+-- Functions that extract event data from the queue tables
+-- and store them in the long term storage tables.
+--
+-- Copyright(C) 2004-2012, DeepClone Development
+-- --------------------------------------------------------
+
+
+/*
+ * Entity fields table
+ * -------------------
+ * 
+ * This table, which is filled when the database is created, associates entity
+ * types with fields in the events.field_values table.
+ */
+DROP TABLE IF EXISTS events._entity_fields;
+CREATE TABLE events._entity_fields(
+	efdef_entity	events.entity_field_type NOT NULL PRIMARY KEY ,
+	field_name		NAME NOT NULL ,
+	field_type		NAME NOT NULL
+);
+INSERT INTO events._entity_fields VALUES
+	( 'EMP' , 'empire_id' , 'INT' ) ,
+	( 'PLN' , 'planet_id' , 'INT' ) ,
+	( 'FLT' , 'fleet_id' , 'BIGINT' ) ,
+	( 'ALL' , 'alliance_id' , 'INT' ) ,
+	( 'BAT' , 'battle_id' , 'BIGINT' ) ,
+	( 'ADM' , 'admin_id' , 'INT' ) ,
+	( 'BUG' , 'bug_report_id' , 'BIGINT' );
+
+
+
+/*
+ * Process a pending event
+ * -----------------------
+ * 
+ * /!\ INTERNAL FUNCTION /!\
+ * 
+ * This procedure processes a single row from an event queue.
+ * 
+ * If the specified event identifier actually exists in the queue, it is
+ * converted and stored in the main events tables, then the queue entry is
+ * removed.
+ * 
+ * In all cases, the entry is deleted from events.pending_events.
+ * 
+ * Parameters:
+ *		_event_id	The event's identifier
+ *		_evdef_id	The event's type
+ *
+ * Returns:
+ *		???			TRUE 
+ */
+DROP FUNCTION IF EXISTS events.eq_process_event( BIGINT , TEXT );
+CREATE FUNCTION events.eq_process_event(
+			_event_id	BIGINT ,
+			_evdef_id	TEXT )
+		RETURNS BOOLEAN
+		LANGUAGE PLPGSQL
+		STRICT VOLATILE SECURITY INVOKER
+	AS $eq_process_event$
+
+DECLARE
+	_tbl	TEXT;
+	_qstr	TEXT;
+	_qentry	RECORD;
+	_nfound	INT;
+	_efdef	RECORD;
+
+BEGIN
+	
+	_tbl := 'events.eq_' || replace( _evdef_id , '-' , '_' );
+	_qstr := 'SELECT event_rtime , event_gtime , empire_id FROM '
+		|| _tbl || ' WHERE event_id = $1';
+	EXECUTE _qstr INTO _qentry USING _event_id;
+	GET DIAGNOSTICS _nfound = ROW_COUNT;
+
+	IF _nfound > 0
+	THEN
+	
+		INSERT INTO events.events_v2 (
+				event_id , evdef_id , event_rtime , event_gtime , empire_id
+			) VALUES (
+				_event_id , _evdef_id , _qentry.event_rtime ,
+				_qentry.event_gtime , _qentry.empire_id
+			);
+
+		_qstr := format( $field_acquisition$
+			SELECT efdef_id , field_name , field_type ,
+					( efdef_type = 'I18N') AS i18n , _sq1.value 
+				FROM events.field_definitions
+					INNER JOIN (
+						SELECT (each(hstore(_tbl))).*
+							FROM %s _tbl
+							WHERE _tbl.event_id = $1
+						) _sq1 ON _sq1.key = 'ef_' || replace(efdef_id , '-','_')
+					LEFT OUTER JOIN events._entity_fields
+						USING ( efdef_entity )
+				WHERE evdef_id = $2
+		$field_acquisition$ , _tbl );
+
+		FOR _efdef IN EXECUTE _qstr USING _event_id , _evdef_id
+		LOOP
+			_qstr := 'INSERT INTO events.field_values(event_id,evdef_id,efdef_id,efval_litteral'
+				|| ( CASE 
+					WHEN _efdef.field_name IS NOT NULL
+						THEN ',' || _efdef.field_name
+					WHEN _efdef.i18n
+						THEN ',string_id'
+					ELSE
+						''
+				END ) || ') ';
+
+			IF _efdef.i18n
+			THEN
+				_qstr := _qstr || $i18n_query$
+					SELECT $1,$2,$3,_str.id::TEXT||' '||_str.name,_str.id
+						FROM defs.strings _str
+						WHERE _str.name = $4
+					$i18n_query$;
+			ELSIF _efdef.field_name IS NOT NULL
+			THEN
+				_qstr := _qstr || format( 'VALUES($1,$2,$3,$4,$4::%s)' , _efdef.field_type );
+			ELSE
+				_qstr := _qstr || 'VALUES($1,$2,$3,$4)';
+			END IF;
+
+			EXECUTE _qstr USING _event_id , _evdef_id , _efdef.efdef_id , _efdef.value;
+		END LOOP;
+
+	END IF;
+
+	DELETE FROM events.pending_events
+		WHERE event_id = _event_id;
+	RETURN TRUE;
+
+END;
+$eq_process_event$;
+
+REVOKE EXECUTE
+	ON FUNCTION events.eq_process_event( BIGINT , TEXT )
+	FROM PUBLIC;
+
+
+
+/*
+ * Process pending events
+ * ----------------------
+ * 
+ * This procedure processes events from the queues. Each time the procedure is
+ * called, it will process at most "game.events.batchSize" events.
+ *
+ * Returns:
+ *		???			TRUE if events were processed, FALSE if the queues are
+ *						empty
+ */
+DROP FUNCTION IF EXISTS events.eq_process( );
+CREATE FUNCTION events.eq_process( )
+		RETURNS BOOLEAN
+		LANGUAGE PLPGSQL
+		STRICT VOLATILE SECURITY DEFINER
+	AS $eq_process$
+
+DECLARE
+	_limit	INT;
+
+BEGIN
+	_limit := sys.get_constant( 'game.events.batchSize' );
+	PERFORM events.eq_process_event( event_id , evdef_id )
+		FROM events.pending_events
+		LIMIT _limit;
+	RETURN FOUND;
+END;
+$eq_process$;
+
+REVOKE EXECUTE
+	ON FUNCTION events.eq_process( )
+	FROM PUBLIC;
+GRANT EXECUTE
+	ON FUNCTION events.eq_process( )
+	TO :dbuser;
\ No newline at end of file