From dc9ef2292d82437ceb209264ce76bb4f033ce07b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emmanuel=20Beno=C3=AEt?= Date: Sun, 1 Jul 2012 01:04:26 +0200 Subject: [PATCH] Event-related functions split Because the events management functions are definitely going to be quite big, I thought it would be better to split them into multiple SQL files. For now, there's a file for event definition functions and one for functions that manipulate priority overrides. The old file containing the old code stays around for now. --- .../040-functions/170-event-definitions.sql | 865 +++++++++++++++ .../parts/040-functions/170-events.sql | 998 ------------------ .../040-functions/171-event-priorities.sql | 143 +++ 3 files changed, 1008 insertions(+), 998 deletions(-) create mode 100644 legacyworlds-server-data/db-structure/parts/040-functions/170-event-definitions.sql create mode 100644 legacyworlds-server-data/db-structure/parts/040-functions/171-event-priorities.sql 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 new file mode 100644 index 0000000..564c971 --- /dev/null +++ b/legacyworlds-server-data/db-structure/parts/040-functions/170-event-definitions.sql @@ -0,0 +1,865 @@ +-- LegacyWorlds Beta 6 +-- PostgreSQL database scripts +-- +-- Functions allowing event definitions to be added to the +-- database +-- +-- 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' , + + /* An internationalised string (either an event type's name or template) + * could not be found. + */ + 'BAD_STRINGS' , + + /* 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' , + + /* This error code is returned when trying to finalise an event after one + * of the definition calls failed. + */ + 'NO_DATA' +); + + + +/* + * 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. + * _i18n The "base" of the I18N strings identifiers; the function + * will attempt to use "<_i18n>Name" as the name's + * identifier and "<_i18n>Template" as the template's. + * + * Returns: + * ??? An error code: OK or BAD_ID + * (see events.evdef_create_result) + */ +DROP FUNCTION IF EXISTS events.evdef_start( TEXT , INT , BOOLEAN , TEXT ); +CREATE FUNCTION events.evdef_start( + _id TEXT , + _prio INT , + _adj BOOLEAN , + _i18n TEXT ) + RETURNS events.evdef_create_result + LANGUAGE PLPGSQL + STRICT VOLATILE SECURITY DEFINER + AS $evdef_start$ + +DECLARE + _name_id INT; + _template_id INT; + +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'; + END IF; + + SELECT INTO _name_id id FROM defs.strings + WHERE name = _i18n || 'Name'; + SELECT INTO _template_id id FROM defs.strings + WHERE name = _i18n || 'Template'; + IF _name_id IS NULL OR _template_id IS NULL THEN + RETURN 'BAD_STRINGS'; + END IF; + + INSERT INTO evdef_temp( evdef_id , evfld_typespec ) + VALUES( _id , _prio::TEXT || ',' || _adj::TEXT + || ',' || _name_id || ',' || _template_id ); + RETURN 'OK'; +END; +$evdef_start$; + +REVOKE EXECUTE + ON FUNCTION events.evdef_start( TEXT , INT , BOOLEAN , TEXT ) + FROM PUBLIC; +GRANT EXECUTE + ON FUNCTION events.evdef_start( TEXT , INT , BOOLEAN , TEXT ) + 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 + DELETE FROM evdef_temp; + 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; + IF NOT FOUND + THEN + RETURN 'NO_DATA'; + END IF; + + _qstr := 'INSERT INTO events.event_definitions (' || + 'evdef_id , evdef_priority , evdef_adjustable , ' || + 'evdef_name_id , evdef_template_id' || + ') 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; 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 db7be76..75fe701 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 @@ -7,1004 +7,6 @@ -- -------------------------------------------------------- -/* - * 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' , - - /* An internationalised string (either an event type's name or template) - * could not be found. - */ - 'BAD_STRINGS' , - - /* 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' , - - /* This error code is returned when trying to finalise an event after one - * of the definition calls failed. - */ - 'NO_DATA' -); - - - -/* - * 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. - * _i18n The "base" of the I18N strings identifiers; the function - * will attempt to use "<_i18n>Name" as the name's - * identifier and "<_i18n>Template" as the template's. - * - * Returns: - * ??? An error code: OK or BAD_ID - * (see events.evdef_create_result) - */ -DROP FUNCTION IF EXISTS events.evdef_start( TEXT , INT , BOOLEAN , TEXT ); -CREATE FUNCTION events.evdef_start( - _id TEXT , - _prio INT , - _adj BOOLEAN , - _i18n TEXT ) - RETURNS events.evdef_create_result - LANGUAGE PLPGSQL - STRICT VOLATILE SECURITY DEFINER - AS $evdef_start$ - -DECLARE - _name_id INT; - _template_id INT; - -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'; - END IF; - - SELECT INTO _name_id id FROM defs.strings - WHERE name = _i18n || 'Name'; - SELECT INTO _template_id id FROM defs.strings - WHERE name = _i18n || 'Template'; - IF _name_id IS NULL OR _template_id IS NULL THEN - RETURN 'BAD_STRINGS'; - END IF; - - INSERT INTO evdef_temp( evdef_id , evfld_typespec ) - VALUES( _id , _prio::TEXT || ',' || _adj::TEXT - || ',' || _name_id || ',' || _template_id ); - RETURN 'OK'; -END; -$evdef_start$; - -REVOKE EXECUTE - ON FUNCTION events.evdef_start( TEXT , INT , BOOLEAN , TEXT ) - FROM PUBLIC; -GRANT EXECUTE - ON FUNCTION events.evdef_start( TEXT , INT , BOOLEAN , TEXT ) - 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 - DELETE FROM evdef_temp; - 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; - IF NOT FOUND - THEN - RETURN 'NO_DATA'; - END IF; - - _qstr := 'INSERT INTO events.event_definitions (' || - 'evdef_id , evdef_priority , evdef_adjustable , ' || - 'evdef_name_id , evdef_template_id' || - ') 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; - - - -/* - * Set an event priority override - * ------------------------------ - * - * Adds a new event priority override or modify its value. If the event type - * does not exist, does not allow overrides or if the specified priority is - * invalid, the error will be ignored silently. - * - * Parameters: - * _empire_id The identifier of the player's empire - * _evdef_id The identifier of the event type - * _priority The custom priority value - */ -DROP FUNCTION IF EXISTS events.evcp_set( INT , TEXT , INT ); -CREATE FUNCTION events.evcp_set( - _empire_id INT , - _evdef_id TEXT , - _priority INT ) - RETURNS VOID - LANGUAGE PLPGSQL - STRICT VOLATILE SECURITY DEFINER - AS $evcp_set$ - -DECLARE - _user_id INT; - -BEGIN - BEGIN - INSERT INTO events.custom_priorities( - evdef_id , address_id , evcp_priority ) - SELECT _evdef_id , owner_id , _priority - FROM naming.empire_names - WHERE id = _empire_id; - IF NOT FOUND - THEN - RAISE EXCEPTION 'missing empire'; - END IF; - EXCEPTION - WHEN unique_violation THEN - UPDATE events.custom_priorities - SET evcp_priority = _priority - WHERE evdef_id = _evdef_id - AND address_id = ( - SELECT owner_id - FROM naming.empire_names - WHERE id = _empire_id ); - END; - -EXCEPTION - WHEN raise_exception THEN - PERFORM sys.write_sql_log( 'Events' , 'WARNING'::log_level , - 'Call to events.evcp_set() from missing empire #' || _empire_id ); - - WHEN foreign_key_violation OR check_violation THEN - PERFORM sys.write_sql_log( 'Events' , 'WARNING'::log_level , - 'Bad call to events.evcp_set() from empire #' || _empire_id ); -END; -$evcp_set$; - -REVOKE EXECUTE - ON FUNCTION events.evcp_set( INT , TEXT , INT ) - FROM PUBLIC; -GRANT EXECUTE - ON FUNCTION events.evcp_set( INT , TEXT , INT ) - TO :dbuser; - - - -/* - * Clear an event priority override - * -------------------------------- - * - * Remove an event priority override from the custom priorities table. If - * there was no override for the specified event type and empire, do nothing. - * - * Parameters: - * _empire_id The identifier of the player's empire - * _evdef_id The identifier of the event type - */ -DROP FUNCTION IF EXISTS events.evcp_clear( INT , TEXT ); -CREATE FUNCTION events.evcp_clear( - _empire_id INT , - _evdef_id TEXT ) - RETURNS VOID - LANGUAGE SQL - STRICT VOLATILE SECURITY DEFINER -AS $evcp_clear$ - DELETE FROM events.custom_priorities - WHERE evdef_id = $2 - AND address_id = ( - SELECT owner_id - FROM naming.empire_names - WHERE id = $1 ) -$evcp_clear$; - -REVOKE EXECUTE - ON FUNCTION events.evcp_clear( INT , TEXT ) - FROM PUBLIC; -GRANT EXECUTE - ON FUNCTION events.evcp_clear( INT , TEXT ) - TO :dbuser; - - - -/* - * Clear all event priority overrides - * ---------------------------------- - * - * Remove all event priority overrides set by some player. - * - * Parameters: - * _empire_id The identifier of the player's empire - */ -DROP FUNCTION IF EXISTS events.evcp_clear( INT ); -CREATE FUNCTION events.evcp_clear( _empire_id INT ) - RETURNS VOID - LANGUAGE SQL - STRICT VOLATILE SECURITY DEFINER -AS $evcp_clear$ - DELETE FROM events.custom_priorities - WHERE address_id = ( - SELECT owner_id - FROM naming.empire_names - WHERE id = $1 ) -$evcp_clear$; - -REVOKE EXECUTE - ON FUNCTION events.evcp_clear( INT ) - FROM PUBLIC; -GRANT EXECUTE - ON FUNCTION events.evcp_clear( INT ) - TO :dbuser; - - - -/* - * OLD B6M1 CODE BELOW! - */ - - -- --------------------------------------------------------------------------------------------------------------------------------------------------------------- -- -- --------------------------------------------------------------------------------------------------------------------------------------------------------------- -- diff --git a/legacyworlds-server-data/db-structure/parts/040-functions/171-event-priorities.sql b/legacyworlds-server-data/db-structure/parts/040-functions/171-event-priorities.sql new file mode 100644 index 0000000..ca67917 --- /dev/null +++ b/legacyworlds-server-data/db-structure/parts/040-functions/171-event-priorities.sql @@ -0,0 +1,143 @@ +-- LegacyWorlds Beta 6 +-- PostgreSQL database scripts +-- +-- Functions to manipulate player-defined event priority +-- overrides. +-- +-- Copyright(C) 2004-2012, DeepClone Development +-- -------------------------------------------------------- + + + +/* + * Set an event priority override + * ------------------------------ + * + * Adds a new event priority override or modify its value. If the event type + * does not exist, does not allow overrides or if the specified priority is + * invalid, the error will be ignored silently. + * + * Parameters: + * _empire_id The identifier of the player's empire + * _evdef_id The identifier of the event type + * _priority The custom priority value + */ +DROP FUNCTION IF EXISTS events.evcp_set( INT , TEXT , INT ); +CREATE FUNCTION events.evcp_set( + _empire_id INT , + _evdef_id TEXT , + _priority INT ) + RETURNS VOID + LANGUAGE PLPGSQL + STRICT VOLATILE SECURITY DEFINER + AS $evcp_set$ + +DECLARE + _user_id INT; + +BEGIN + BEGIN + INSERT INTO events.custom_priorities( + evdef_id , address_id , evcp_priority ) + SELECT _evdef_id , owner_id , _priority + FROM naming.empire_names + WHERE id = _empire_id; + IF NOT FOUND + THEN + RAISE EXCEPTION 'missing empire'; + END IF; + EXCEPTION + WHEN unique_violation THEN + UPDATE events.custom_priorities + SET evcp_priority = _priority + WHERE evdef_id = _evdef_id + AND address_id = ( + SELECT owner_id + FROM naming.empire_names + WHERE id = _empire_id ); + END; + +EXCEPTION + WHEN raise_exception THEN + PERFORM sys.write_sql_log( 'Events' , 'WARNING'::log_level , + 'Call to events.evcp_set() from missing empire #' || _empire_id ); + + WHEN foreign_key_violation OR check_violation THEN + PERFORM sys.write_sql_log( 'Events' , 'WARNING'::log_level , + 'Bad call to events.evcp_set() from empire #' || _empire_id ); +END; +$evcp_set$; + +REVOKE EXECUTE + ON FUNCTION events.evcp_set( INT , TEXT , INT ) + FROM PUBLIC; +GRANT EXECUTE + ON FUNCTION events.evcp_set( INT , TEXT , INT ) + TO :dbuser; + + + +/* + * Clear an event priority override + * -------------------------------- + * + * Remove an event priority override from the custom priorities table. If + * there was no override for the specified event type and empire, do nothing. + * + * Parameters: + * _empire_id The identifier of the player's empire + * _evdef_id The identifier of the event type + */ +DROP FUNCTION IF EXISTS events.evcp_clear( INT , TEXT ); +CREATE FUNCTION events.evcp_clear( + _empire_id INT , + _evdef_id TEXT ) + RETURNS VOID + LANGUAGE SQL + STRICT VOLATILE SECURITY DEFINER +AS $evcp_clear$ + DELETE FROM events.custom_priorities + WHERE evdef_id = $2 + AND address_id = ( + SELECT owner_id + FROM naming.empire_names + WHERE id = $1 ) +$evcp_clear$; + +REVOKE EXECUTE + ON FUNCTION events.evcp_clear( INT , TEXT ) + FROM PUBLIC; +GRANT EXECUTE + ON FUNCTION events.evcp_clear( INT , TEXT ) + TO :dbuser; + + + +/* + * Clear all event priority overrides + * ---------------------------------- + * + * Remove all event priority overrides set by some player. + * + * Parameters: + * _empire_id The identifier of the player's empire + */ +DROP FUNCTION IF EXISTS events.evcp_clear( INT ); +CREATE FUNCTION events.evcp_clear( _empire_id INT ) + RETURNS VOID + LANGUAGE SQL + STRICT VOLATILE SECURITY DEFINER +AS $evcp_clear$ + DELETE FROM events.custom_priorities + WHERE address_id = ( + SELECT owner_id + FROM naming.empire_names + WHERE id = $1 ) +$evcp_clear$; + +REVOKE EXECUTE + ON FUNCTION events.evcp_clear( INT ) + FROM PUBLIC; +GRANT EXECUTE + ON FUNCTION events.evcp_clear( INT ) + TO :dbuser;