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 121b26a..40350e8 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 @@ -63,6 +63,8 @@ CREATE TYPE events.entity_field_type AS ENUM( 'PLN' , /* A fleet */ 'FLT' , + /* An alliance */ + 'ALL' , /* A battle */ 'BAT' , /* An administrator */ @@ -159,6 +161,18 @@ ALTER TABLE events.field_definitions GRANT SELECT ON events.field_definitions TO :dbuser; +/* + * Event identifier sequence + * ------------------------- + * + * This sequence is used by the various type-specific event queues to + * generate the events' identifiers. + */ +DROP SEQUENCE IF EXISTS events.event_id_sequence CASCADE; +CREATE SEQUENCE events.event_id_sequence; +GRANT SELECT,UPDATE ON events.event_id_sequence TO :dbuser; + + /* * OLD B6M1 CODE BELOW! diff --git a/legacyworlds-server-data/db-structure/parts/040-functions/170-events.sql b/legacyworlds-server-data/db-structure/parts/040-functions/170-events.sql index 9e63f90..472eb73 100644 --- a/legacyworlds-server-data/db-structure/parts/040-functions/170-events.sql +++ b/legacyworlds-server-data/db-structure/parts/040-functions/170-events.sql @@ -3,10 +3,836 @@ -- -- Functions and views to create and manipulate events -- --- Copyright(C) 2004-2010, DeepClone Development +-- Copyright(C) 2004-2012, DeepClone Development -- -------------------------------------------------------- +/* + * Return values for event definition functions + * --------------------------------------------- + */ +DROP TYPE IF EXISTS events.evdef_create_result CASCADE; +CREATE TYPE events.evdef_create_result AS ENUM( + /* The event type definition function succeeded. If it was the initial + * creation function or a field creation function, this means the creation + * can continue. If it was the finalisation function, this means the event + * definition has been added. + */ + 'OK' , + + /* A bad identifier was specified. This value is returned by both the + * initial creation function and event field definition functions. + */ + 'BAD_ID' , + + /* Duplicate event or field identifier found. This value is returned by + * the finalisation function, with its "_fld" set to NULL if the duplicate + * identifier is the event's. + */ + 'DUPLICATE' , + + /* Bad event or field specification found. This value is returned by the + * finalisation function when an event or field cannot be inserted due to + * check failures. + */ + 'BAD_SPEC' +); + + + +/* + * Start defining a new event type + * ------------------------------- + * + * This function creates a temporary table used to defgine a new type of + * event. No checks beyond the length and contents of the event type's + * identifier are made at this point. + * + * Note: the temporary table will be created in all cases, even when the + * identifier is invalid. + * + * Parameters: + * _id The identifier of the event type + * _prio The event type's default priority + * _adj Whether the player may adjust the priority for this type + * of events. + * + * Returns: + * ??? An error code: OK or BAD_ID + * (see events.evdef_create_result) + */ +DROP FUNCTION IF EXISTS events.evdef_start( TEXT , INT , BOOLEAN ); +CREATE FUNCTION events.evdef_start( _id TEXT , _prio INT , _adj BOOLEAN ) + RETURNS events.evdef_create_result + LANGUAGE PLPGSQL + STRICT VOLATILE SECURITY DEFINER + AS $evdef_start$ +BEGIN + CREATE TEMPORARY TABLE evdef_temp( + evdef_id TEXT , + evfld_id TEXT , + evfld_typespec TEXT + ) ON COMMIT DROP; + + IF LENGTH( _id ) < 2 OR LENGTH( _id ) > 48 + OR NOT _id ~ '^[a-z\-]+$' + THEN + RETURN 'BAD_ID'::events.evdef_create_result; + END IF; + + INSERT INTO evdef_temp( evdef_id , evfld_typespec ) + VALUES( _id , _prio::TEXT || ' , ' || _adj::TEXT ); + RETURN 'OK'::events.evdef_create_result; +END; +$evdef_start$; + +REVOKE EXECUTE + ON FUNCTION events.evdef_start( TEXT , INT , BOOLEAN ) + FROM PUBLIC; +GRANT EXECUTE + ON FUNCTION events.evdef_start( TEXT , INT , BOOLEAN ) + TO :dbuser; + + + +/* + * Create a new field + * ------------------ + * + * /!\ INTERNAL FUNCTION /!\ + * + * This function adds data about a new field to the temporary event + * definition table. + * + * Parameters: + * _id The field's identifier + * _opt Whether the field is optional + * _type The field's type + * _etype The field's entity type (may be NULL) + * _is_int Whether the field is an integer (may be NULL) + * _min_val Minimal value/length (may be NULL) + * _max_val Maximal value/length (may be NULL) + * + * Returns: + * ??? An error code: OK or BAD_ID + * (see events.evdef_create_result) + */ +DROP FUNCTION IF EXISTS events.evdef_addfld_internal( + TEXT , BOOLEAN , events.field_type , events.entity_field_type , + BOOLEAN , NUMERIC , NUMERIC ) CASCADE; +CREATE FUNCTION events.evdef_addfld_internal( + _id TEXT , + _opt BOOLEAN , + _type events.field_type , + _etype events.entity_field_type , + _is_int BOOLEAN , + _min_val NUMERIC , + _max_val NUMERIC + ) RETURNS events.evdef_create_result + LANGUAGE PLPGSQL + CALLED ON NULL INPUT + VOLATILE SECURITY INVOKER + AS $evdef_addfld_internal$ + +DECLARE + _iq_string TEXT; + +BEGIN + IF LENGTH( _id ) < 2 OR LENGTH( _id ) > 48 + OR NOT _id ~ '^[a-z\-]+$' + THEN + RETURN 'BAD_ID'::events.evdef_create_result; + END IF; + + _iq_string := _opt::TEXT || ' , ''' || _type::TEXT || ''' , '; + IF _etype IS NULL + THEN + _iq_string := _iq_string || 'NULL'; + ELSE + _iq_string := _iq_string || '''' || _etype::TEXT || ''''; + END IF; + _iq_string := _iq_string || ' , '; + IF _is_int IS NULL + THEN + _iq_string := _iq_string || 'NULL'; + ELSE + _iq_string := _iq_string || _is_int::TEXT; + END IF; + _iq_string := _iq_string || ' , '; + IF _min_val IS NULL + THEN + _iq_string := _iq_string || 'NULL'; + ELSE + _iq_string := _iq_string || _min_val::TEXT; + END IF; + _iq_string := _iq_string || ' , '; + IF _max_val IS NULL + THEN + _iq_string := _iq_string || 'NULL'; + ELSE + _iq_string := _iq_string || _max_val::TEXT; + END IF; + + INSERT INTO evdef_temp( evdef_id , evfld_id , evfld_typespec ) + SELECT evdef_id , _id , _iq_string + FROM evdef_temp + WHERE evfld_id IS NULL; + RETURN 'OK'::events.evdef_create_result; +END; +$evdef_addfld_internal$; + +REVOKE EXECUTE + ON FUNCTION events.evdef_addfld_internal( + TEXT , BOOLEAN , events.field_type , events.entity_field_type , + BOOLEAN , NUMERIC , NUMERIC ) + FROM PUBLIC; + + +/* + * Actual field creation functions + * -------------------------------- + * + * Bunch of functions that create the field records in the temporary table + * through events.evdef_addfld_internal(). + * + * Note: + * These functions are not dropped manually here, as it is assumed that + * dropping events.evdef_addfld_internal() will have cascaded. + */ + +-- INTEGER FIELD, NO BOUNDS +CREATE FUNCTION events.evdef_addfld_int( _id TEXT , _opt BOOLEAN ) + RETURNS events.evdef_create_result + LANGUAGE SQL + STRICT VOLATILE SECURITY DEFINER + AS $$ SELECT events.evdef_addfld_internal( + $1,$2,'NUMERIC'::events.field_type,NULL,TRUE,NULL,NULL); $$; +REVOKE EXECUTE + ON FUNCTION events.evdef_addfld_int( TEXT , BOOLEAN ) + FROM PUBLIC; +GRANT EXECUTE + ON FUNCTION events.evdef_addfld_int( TEXT , BOOLEAN ) + TO :dbuser; + +-- INTEGER FIELD W/ LOWER BOUND +CREATE FUNCTION events.evdef_addfld_int_min( _id TEXT , _opt BOOLEAN , _min INT ) + RETURNS events.evdef_create_result + LANGUAGE SQL + STRICT VOLATILE SECURITY DEFINER + AS $$ SELECT events.evdef_addfld_internal( + $1,$2,'NUMERIC'::events.field_type,NULL,TRUE,$3::NUMERIC,NULL); $$; +REVOKE EXECUTE + ON FUNCTION events.evdef_addfld_int_min( TEXT , BOOLEAN , INT ) + FROM PUBLIC; +GRANT EXECUTE + ON FUNCTION events.evdef_addfld_int_min( TEXT , BOOLEAN , INT ) + TO :dbuser; + +-- INTEGER FIELD W/ HIGHER BOUND +CREATE FUNCTION events.evdef_addfld_int_max( _id TEXT , _opt BOOLEAN , _max INT ) + RETURNS events.evdef_create_result + LANGUAGE SQL + STRICT VOLATILE SECURITY DEFINER + AS $$ SELECT events.evdef_addfld_internal( + $1,$2,'NUMERIC'::events.field_type,NULL,TRUE,NULL,$3::NUMERIC); $$; +REVOKE EXECUTE + ON FUNCTION events.evdef_addfld_int_max( TEXT , BOOLEAN , INT ) + FROM PUBLIC; +GRANT EXECUTE + ON FUNCTION events.evdef_addfld_int_max( TEXT , BOOLEAN , INT ) + TO :dbuser; + +-- INTEGER FIELD W/ LIMITED RANGE +CREATE FUNCTION events.evdef_addfld_int_range( _id TEXT , _opt BOOLEAN , _min INT , _max INT ) + RETURNS events.evdef_create_result + LANGUAGE SQL + STRICT VOLATILE SECURITY DEFINER + AS $$ SELECT events.evdef_addfld_internal( + $1,$2,'NUMERIC'::events.field_type,NULL,TRUE,$3::NUMERIC,$4::NUMERIC); $$; +REVOKE EXECUTE + ON FUNCTION events.evdef_addfld_int_range( TEXT , BOOLEAN , INT , INT ) + FROM PUBLIC; +GRANT EXECUTE + ON FUNCTION events.evdef_addfld_int_range( TEXT , BOOLEAN , INT , INT ) + TO :dbuser; + +-- REAL FIELD, NO BOUNDS +CREATE FUNCTION events.evdef_addfld_real( _id TEXT , _opt BOOLEAN ) + RETURNS events.evdef_create_result + LANGUAGE SQL + STRICT VOLATILE SECURITY DEFINER + AS $$ SELECT events.evdef_addfld_internal( + $1,$2,'NUMERIC'::events.field_type,NULL,FALSE,NULL,NULL); $$; +REVOKE EXECUTE + ON FUNCTION events.evdef_addfld_real( TEXT , BOOLEAN ) + FROM PUBLIC; +GRANT EXECUTE + ON FUNCTION events.evdef_addfld_real( TEXT , BOOLEAN ) + TO :dbuser; + +-- REAL FIELD W/ LOWER BOUND +CREATE FUNCTION events.evdef_addfld_real_min( _id TEXT , _opt BOOLEAN , _min DOUBLE PRECISION ) + RETURNS events.evdef_create_result + LANGUAGE SQL + STRICT VOLATILE SECURITY DEFINER + AS $$ SELECT events.evdef_addfld_internal( + $1,$2,'NUMERIC'::events.field_type,NULL,FALSE,$3::NUMERIC,NULL); $$; +REVOKE EXECUTE + ON FUNCTION events.evdef_addfld_real_min( TEXT , BOOLEAN , DOUBLE PRECISION ) + FROM PUBLIC; +GRANT EXECUTE + ON FUNCTION events.evdef_addfld_real_min( TEXT , BOOLEAN , DOUBLE PRECISION ) + TO :dbuser; + +-- REAL FIELD W/ HIGHER BOUND +CREATE FUNCTION events.evdef_addfld_real_max( _id TEXT , _opt BOOLEAN , _max DOUBLE PRECISION ) + RETURNS events.evdef_create_result + LANGUAGE SQL + STRICT VOLATILE SECURITY DEFINER + AS $$ SELECT events.evdef_addfld_internal( + $1,$2,'NUMERIC'::events.field_type,NULL,FALSE,NULL,$3::NUMERIC); $$; +REVOKE EXECUTE + ON FUNCTION events.evdef_addfld_real_max( TEXT , BOOLEAN , DOUBLE PRECISION ) + FROM PUBLIC; +GRANT EXECUTE + ON FUNCTION events.evdef_addfld_real_max( TEXT , BOOLEAN , DOUBLE PRECISION ) + TO :dbuser; + +-- REAL FIELD W/ LIMITED RANGE +CREATE FUNCTION events.evdef_addfld_real_range( _id TEXT , _opt BOOLEAN , _min DOUBLE PRECISION , _max DOUBLE PRECISION ) + RETURNS events.evdef_create_result + LANGUAGE SQL + STRICT VOLATILE SECURITY DEFINER + AS $$ SELECT events.evdef_addfld_internal( + $1,$2,'NUMERIC'::events.field_type,NULL,FALSE,$3::NUMERIC,$4::NUMERIC); $$; +REVOKE EXECUTE + ON FUNCTION events.evdef_addfld_real_range( TEXT , BOOLEAN , DOUBLE PRECISION , DOUBLE PRECISION ) + FROM PUBLIC; +GRANT EXECUTE + ON FUNCTION events.evdef_addfld_real_range( TEXT , BOOLEAN , DOUBLE PRECISION , DOUBLE PRECISION ) + TO :dbuser; + +-- TEXT FIELD, NO BOUNDS +CREATE FUNCTION events.evdef_addfld_text( _id TEXT , _opt BOOLEAN ) + RETURNS events.evdef_create_result + LANGUAGE SQL + STRICT VOLATILE SECURITY DEFINER + AS $$ SELECT events.evdef_addfld_internal( + $1,$2,'TEXT'::events.field_type,NULL,NULL,NULL,NULL); $$; +REVOKE EXECUTE + ON FUNCTION events.evdef_addfld_text( TEXT , BOOLEAN ) + FROM PUBLIC; +GRANT EXECUTE + ON FUNCTION events.evdef_addfld_text( TEXT , BOOLEAN ) + TO :dbuser; + +-- TEXT FIELD W/ LOWER BOUND +CREATE FUNCTION events.evdef_addfld_text_min( _id TEXT , _opt BOOLEAN , _min INT ) + RETURNS events.evdef_create_result + LANGUAGE SQL + STRICT VOLATILE SECURITY DEFINER + AS $$ SELECT events.evdef_addfld_internal( + $1,$2,'TEXT'::events.field_type,NULL,NULL,$3::NUMERIC,NULL); $$; +REVOKE EXECUTE + ON FUNCTION events.evdef_addfld_text_min( TEXT , BOOLEAN , INT ) + FROM PUBLIC; +GRANT EXECUTE + ON FUNCTION events.evdef_addfld_text_min( TEXT , BOOLEAN , INT ) + TO :dbuser; + +-- TEXT FIELD W/ HIGHER BOUND +CREATE FUNCTION events.evdef_addfld_text_max( _id TEXT , _opt BOOLEAN , _max INT ) + RETURNS events.evdef_create_result + LANGUAGE SQL + STRICT VOLATILE SECURITY DEFINER + AS $$ SELECT events.evdef_addfld_internal( + $1,$2,'TEXT'::events.field_type,NULL,NULL,NULL,$3::NUMERIC); $$; +REVOKE EXECUTE + ON FUNCTION events.evdef_addfld_text_max( TEXT , BOOLEAN , INT ) + FROM PUBLIC; +GRANT EXECUTE + ON FUNCTION events.evdef_addfld_text_max( TEXT , BOOLEAN , INT ) + TO :dbuser; + +-- TEXT FIELD W/ LIMITED RANGE +CREATE FUNCTION events.evdef_addfld_text_range( _id TEXT , _opt BOOLEAN , _min INT , _max INT ) + RETURNS events.evdef_create_result + LANGUAGE SQL + STRICT VOLATILE SECURITY DEFINER + AS $$ SELECT events.evdef_addfld_internal( + $1,$2,'TEXT'::events.field_type,NULL,NULL,$3::NUMERIC,$4::NUMERIC); $$; +REVOKE EXECUTE + ON FUNCTION events.evdef_addfld_text_range( TEXT , BOOLEAN , INT , INT ) + FROM PUBLIC; +GRANT EXECUTE + ON FUNCTION events.evdef_addfld_text_range( TEXT , BOOLEAN , INT , INT ) + TO :dbuser; + +-- BOOLEAN FIELD +CREATE FUNCTION events.evdef_addfld_bool( _id TEXT , _opt BOOLEAN ) + RETURNS events.evdef_create_result + LANGUAGE SQL + STRICT VOLATILE SECURITY DEFINER + AS $$ SELECT events.evdef_addfld_internal( + $1,$2,'BOOL'::events.field_type,NULL,NULL,NULL,NULL); $$; +REVOKE EXECUTE + ON FUNCTION events.evdef_addfld_bool( TEXT , BOOLEAN ) + FROM PUBLIC; +GRANT EXECUTE + ON FUNCTION events.evdef_addfld_bool( TEXT , BOOLEAN ) + TO :dbuser; + +-- I18N TEXT FIELD +CREATE FUNCTION events.evdef_addfld_i18n( _id TEXT , _opt BOOLEAN ) + RETURNS events.evdef_create_result + LANGUAGE SQL + STRICT VOLATILE SECURITY DEFINER + AS $$ SELECT events.evdef_addfld_internal( + $1,$2,'I18N'::events.field_type,NULL,NULL,NULL,NULL); $$; +REVOKE EXECUTE + ON FUNCTION events.evdef_addfld_i18n( TEXT , BOOLEAN ) + FROM PUBLIC; +GRANT EXECUTE + ON FUNCTION events.evdef_addfld_i18n( TEXT , BOOLEAN ) + TO :dbuser; + +-- ENTITY LINK FIELD +CREATE FUNCTION events.evdef_addfld_entity( _id TEXT , _opt BOOLEAN , _etype events.entity_field_type ) + RETURNS events.evdef_create_result + LANGUAGE SQL + STRICT VOLATILE SECURITY DEFINER + AS $$ SELECT events.evdef_addfld_internal( + $1,$2,'ENTITY'::events.field_type,$3,NULL,NULL,NULL); $$; +REVOKE EXECUTE + ON FUNCTION events.evdef_addfld_entity( TEXT , BOOLEAN , events.entity_field_type ) + FROM PUBLIC; +GRANT EXECUTE + ON FUNCTION events.evdef_addfld_entity( TEXT , BOOLEAN , events.entity_field_type ) + TO :dbuser; + + +/* + * Create an event definition record + * --------------------------------- + * + * /!\ INTERNAL FUNCTION /!\ + * + * This function inserts the record for an event definition into the + * appropriate table. + * + * Returns: + * ??? An error code + */ +DROP FUNCTION IF EXISTS events.evdef_create_record( ); +CREATE FUNCTION events.evdef_create_record( ) + RETURNS events.evdef_create_result + LANGUAGE PLPGSQL + STRICT VOLATILE SECURITY INVOKER + AS $evdef_create_record$ + +DECLARE + _rec RECORD; + _qstr TEXT; + +BEGIN + SELECT INTO _rec * + FROM evdef_temp + WHERE evfld_id IS NULL; + + _qstr := 'INSERT INTO events.event_definitions (' || + 'evdef_id , evdef_priority , evdef_adjustable' || + ') VALUES ( $1 , ' || _rec.evfld_typespec || ');'; + + BEGIN + EXECUTE _qstr USING _rec.evdef_id; + EXCEPTION + WHEN unique_violation THEN + RETURN 'DUPLICATE'; + WHEN check_violation THEN + RETURN 'BAD_SPEC'; + END; + + RETURN 'OK'; +END; +$evdef_create_record$; + +REVOKE EXECUTE + ON FUNCTION events.evdef_create_record( ) + FROM PUBLIC; + + +/* + * Create an event field definition record + * --------------------------------------- + * + * /!\ INTERNAL FUNCTION /!\ + * + * This function inserts a new event field definition record into the + * appropriate table. + * + * Parameters: + * _evdef_id The event definition's identifier + * _efdef_id The field's identifier + * _typespec The type specification from the temporary table + * + * Returns: + * ??? An error code + */ +DROP FUNCTION IF EXISTS events.evdef_create_field_record( + TEXT , TEXT , TEXT ); +CREATE FUNCTION events.evdef_create_field_record( + _evdef_id TEXT , + _efdef_id TEXT , + _typespec TEXT ) + RETURNS events.evdef_create_result + LANGUAGE PLPGSQL + STRICT VOLATILE SECURITY INVOKER + AS $evdef_create_field_record$ + +DECLARE + _qstr TEXT; + +BEGIN + _qstr := 'INSERT INTO events.field_definitions (' || + 'evdef_id , efdef_id , efdef_optional , efdef_type , ' || + 'efdef_entity , efdef_integer , efdef_min , efdef_max ' || + ') VALUES ( $1 , $2 , ' || _typespec || ');'; + BEGIN + EXECUTE _qstr USING _evdef_id , _efdef_id; + EXCEPTION + WHEN unique_violation THEN + RETURN 'DUPLICATE'; + WHEN check_violation THEN + RETURN 'BAD_SPEC'; + END; + RETURN 'OK'; + +END; +$evdef_create_field_record$; + +REVOKE EXECUTE + ON FUNCTION events.evdef_create_field_record( TEXT , TEXT , TEXT ) + FROM PUBLIC; + + +/* + * Generate the DDL for a numeric field + * ------------------------------------ + * + * /!\ INTERNAL FUNCTION /!\ + * + * This function generates the DDL for a numeric event field in an event queue + * table. + * + * Parameters: + * _fname The field's table name + * _opt Whether the field is optional + * _is_int Whether the field is an integer + * _min Minimal value of the field (may be NULL) + * _max Maximal value of the field (may be NULL) + * + * Returns: + * ??? The field's DDL + */ +DROP FUNCTION IF EXISTS events.efdef_ddl_numeric( + TEXT , BOOLEAN , BOOLEAN , NUMERIC , NUMERIC ); +CREATE FUNCTION events.efdef_ddl_numeric( + _fname TEXT , + _opt BOOLEAN , + _is_int BOOLEAN , + _min NUMERIC , + _max NUMERIC ) + RETURNS TEXT + LANGUAGE SQL + IMMUTABLE SECURITY INVOKER + CALLED ON NULL INPUT +AS $efdef_ddl_numeric$ + SELECT ',' || $1 || ' ' + || ( CASE WHEN $3 THEN 'BIGINT' ELSE 'DOUBLE PRECISION' END ) + || ( CASE WHEN $2 THEN '' ELSE ' NOT NULL' END ) + || ( CASE + WHEN $4 IS NULL AND $5 IS NULL + THEN '' + ELSE + ' CHECK(' || $1 || ( CASE + WHEN $5 IS NULL + THEN '>=' || $4::TEXT + WHEN $4 IS NULL + THEN '<=' || $5::TEXT + ELSE + ' BETWEEN ' || $4::TEXT || ' AND ' || $5::TEXT + END ) || ')' + END ); +$efdef_ddl_numeric$; + +REVOKE EXECUTE + ON FUNCTION events.efdef_ddl_numeric( + TEXT , BOOLEAN , BOOLEAN , NUMERIC , NUMERIC ) + FROM PUBLIC; + + + +/* + * Generate the DDL for a text field + * --------------------------------- + * + * /!\ INTERNAL FUNCTION /!\ + * + * This function generates the DDL for a text event field in an event queue + * table. + * + * Parameters: + * _fname The field's table name + * _opt Whether the field is optional + * _min Minimal length of the field (may be NULL) + * _max Maximal length of the field (may be NULL) + * + * Returns: + * ??? The field's DDL + */ +DROP FUNCTION IF EXISTS events.efdef_ddl_text( + TEXT , BOOLEAN , NUMERIC , NUMERIC ); +CREATE FUNCTION events.efdef_ddl_text( + _fname TEXT , + _opt BOOLEAN , + _min NUMERIC , + _max NUMERIC ) + RETURNS TEXT + LANGUAGE SQL + IMMUTABLE SECURITY INVOKER + CALLED ON NULL INPUT +AS $efdef_ddl_text$ + SELECT ',' || $1 || ' ' + || ( CASE WHEN $4 IS NULL THEN 'TEXT' ELSE 'VARCHAR(' || $4::TEXT || ')' END ) + || ( CASE WHEN $2 THEN '' ELSE ' NOT NULL' END ) + || ( CASE + WHEN $3 IS NULL + THEN '' + ELSE + ' CHECK(LENGTH(' || $1 || ')>=' || $3::TEXT || ')' + END ); +$efdef_ddl_text$; + +REVOKE EXECUTE + ON FUNCTION events.efdef_ddl_text( + TEXT , BOOLEAN , NUMERIC , NUMERIC ) + FROM PUBLIC; + + + +/* + * Generate the DDL for an entity field + * ------------------------------------ + * + * /!\ INTERNAL FUNCTION /!\ + * + * This function generates the DDL for an entity event field in an event queue + * table. + * + * Parameters: + * _fname The field's table name + * _opt Whether the field is optional + * _etype Type of entity to reference + * + * Returns: + * ??? The field's DDL + */ +DROP FUNCTION IF EXISTS events.efdef_ddl_entity( + TEXT , BOOLEAN , events.entity_field_type ); +CREATE FUNCTION events.efdef_ddl_entity( + _fname TEXT , + _opt BOOLEAN , + _etype events.entity_field_type ) + RETURNS TEXT + LANGUAGE SQL + STRICT IMMUTABLE SECURITY INVOKER +AS $efdef_ddl_entity$ + SELECT ',' || $1 || ' ' + || ( CASE + WHEN $3 IN ( 'EMP' , 'PLN', 'ALL' , 'ADM' ) THEN 'INT' + ELSE 'BIGINT' + END ) || ( CASE WHEN $2 THEN ' NOT NULL' ELSE '' END ) + || ' REFERENCES ' || ( CASE $3 + WHEN 'EMP' THEN 'emp.empires(name_id)' + WHEN 'PLN' THEN 'verse.planets(name_id)' + WHEN 'FLT' THEN 'fleets.fleets(id)' + WHEN 'ALL' THEN 'emp.alliances(id)' + WHEN 'BAT' THEN 'battles.battles(id)' + WHEN 'ADM' THEN 'admin.administrators(id)' + WHEN 'BUG' THEN 'bugs.initial_report_events(event_id)' + END ) || ' ON DELETE CASCADE'; +$efdef_ddl_entity$; + +REVOKE EXECUTE + ON FUNCTION events.efdef_ddl_entity( + TEXT , BOOLEAN , events.entity_field_type ) + FROM PUBLIC; + + + +/* + * Create the event queuing table for a new definition + * --------------------------------------------------- + * + * /!\ INTERNAL FUNCTION /!\ + * + * This function generates the event queuing table from the list of fields + * that compose an event definition. The queuing table's name will always be + * "events.evq_"; it will contain an event identifier + * generated from the event ID sequence (events.event_id_sequence), an empire + * identifier, a timestamp, the tick identifier, and rows corresponding to the + * event definition's fields. + * + * Parameters: + * _evdef_id The event definition's identifier + */ +DROP FUNCTION IF EXISTS events.evdef_create_queue_table( TEXT ); +CREATE FUNCTION _temp_init_func(_user TEXT) RETURNS VOID LANGUAGE PLPGSQL AS $init_func$ +BEGIN EXECUTE $init_code$ +CREATE FUNCTION events.evdef_create_queue_table( _evdef_id TEXT ) + RETURNS VOID + LANGUAGE PLPGSQL + STRICT VOLATILE SECURITY INVOKER + AS $evdef_create_queue_table$ + +DECLARE + _rec RECORD; + _qstr TEXT; + _fname TEXT; + +BEGIN + + _qstr := 'CREATE TABLE events.eq_' || replace( _evdef_id , '-' , '_' ) + || $tbl_def$ ( + event_id BIGINT NOT NULL PRIMARY KEY + DEFAULT nextval('events.event_id_sequence'::regclass) , + event_rtime TIMESTAMP WITHOUT TIME ZONE NOT NULL + DEFAULT now( ) , + event_gtime BIGINT NOT NULL , + empire_id INT NOT NULL REFERENCES emp.empires ( name_id ) + ON DELETE CASCADE + $tbl_def$; + + FOR _rec IN SELECT * + FROM events.field_definitions + WHERE evdef_id = _evdef_id + LOOP + _fname := 'ef_' || replace( _rec.efdef_id , '-' , '_' ); + _qstr := _qstr || ( CASE _rec.efdef_type + WHEN 'NUMERIC' THEN + events.efdef_ddl_numeric( _fname , _rec.efdef_optional , + _rec.efdef_integer , _rec.efdef_min , _rec.efdef_max ) + WHEN 'TEXT' THEN + events.efdef_ddl_text( _fname , _rec.efdef_optional , + _rec.efdef_min , _rec.efdef_max ) + WHEN 'BOOL' THEN + ',' || _fname || ' BOOLEAN' || ( CASE + WHEN NOT _rec.efdef_optional THEN ' NOT NULL' + ELSE '' + END ) + WHEN 'I18N' THEN + ',' || _fname || ' VARCHAR(64)' || ( CASE + WHEN NOT _rec.efdef_optional THEN ' NOT NULL' + ELSE '' + END ) || ' REFERENCES defs.strings(name)' + WHEN 'ENTITY' THEN + events.efdef_ddl_entity( _fname , _rec.efdef_optional , + _rec.efdef_entity ) + END ); + END LOOP; + + _qstr := _qstr || ');'; + EXECUTE _qstr; + + _qstr := 'GRANT INSERT ON TABLE events.eq_' || replace( _evdef_id , '-' , '_' ) + || ' TO $init_code$ || $1 || $init_code$;'; + EXECUTE _qstr; +END; +$evdef_create_queue_table$; $init_code$ USING $1; END; $init_func$; +SELECT _temp_init_func(:dbuser_string); +DROP FUNCTION _temp_init_func(TEXT); + +REVOKE EXECUTE + ON FUNCTION events.evdef_create_queue_table( TEXT ) + FROM PUBLIC; + + + +/* + * Validate and finalise an event definition + * ----------------------------------------- + * + * This function inserts the contents of the temporary event definition table + * into the main table. If everything goes well, the event queuing table is + * created and the temporary table is destroyed. + * + * Returns: + * _error An error code (see events.evdef_create_result) + * _fld The name of the field which caused the error, or NULL + * if the error was table-related or if there was no + * error. + */ +DROP FUNCTION IF EXISTS events.evdef_finalise( ); +CREATE FUNCTION events.evdef_finalise( + OUT _error events.evdef_create_result , + OUT _fld TEXT ) + LANGUAGE PLPGSQL + STRICT VOLATILE SECURITY DEFINER + AS $evdef_finalise$ + +DECLARE + _eid TEXT; + _rec RECORD; + +BEGIN + -- First create the event definition record + _fld := NULL; + _error := events.evdef_create_record( ); + IF _error = 'OK' + THEN + -- Then create records for all fields + FOR _rec IN SELECT * FROM evdef_temp WHERE evfld_id IS NOT NULL + LOOP + _error := events.evdef_create_field_record( + _rec.evdef_id , _rec.evfld_id , _rec.evfld_typespec ); + + IF _error <> 'OK' + THEN + -- Destroy the definition record on failure + _fld := _rec.evfld_id; + DELETE FROM events.event_definitions + WHERE evdef_id = _rec.evdef_id; + EXIT; + END IF; + + END LOOP; + END IF; + + -- If everything went well so far, create the queueing table + IF _error = 'OK' + THEN + SELECT INTO _eid evdef_id FROM evdef_temp LIMIT 1; + PERFORM events.evdef_create_queue_table( _eid ); + END IF; + + DROP TABLE evdef_temp; +END; +$evdef_finalise$; + +REVOKE EXECUTE + ON FUNCTION events.evdef_finalise( ) + FROM PUBLIC; +GRANT EXECUTE + ON FUNCTION events.evdef_finalise( ) + TO :dbuser; + + +/* + * OLD B6M1 CODE BELOW! + */ + + + -- --------------------------------------------------------------------------------------------------------------------------------------------------------------- -- -- --------------------------------------------------------------------------------------------------------------------------------------------------------------- -- -- EVENT CREATION FUNCTIONS --