-- AREA Database schema to be implemented in 2003 -- Bruno Wolff III -- January 5, 2003 -- Make sure database is set up properly -- First connect as postgres superuser \c - postgres -- Make sure that not everyone can create schemas or temporary tables revoke all on database :DBNAME from public; -- Delete the public schema if it exists drop schema public cascade; -- Create the public schema with limited access begin; create schema public; revoke all on schema public from public; grant usage on schema public to public; grant all on schema public to bruno; end; -- Install the contrib/cube functions. When postgres was installed a -- make install of contrib/cube must have been done. \i cube.sql -- Install the contrib/earthdistance functions. Currently no binary -- earthdistance stuff is being used, so that a make install of -- contrib/earthdistance isn't a prerequisite. \i earthdistance.sql -- Create the AREA administrator group drop group area_admin; create group area_admin; alter group area_admin add user bruno; -- bruno now has enough rights that we can use his account to finish up set session authorization bruno; -- We should now have a clean database with appropiate extensions and -- can set up the AREA specific stuff. -- Privacy -- This table defines privacy attributes. This allows security to be -- enforced by which username an application connects with, rather than -- by having applications include security rules. -- I anticipate codes to allow contact information: -- To be publishable (on the web). -- To be given out in response to special (one off) requests, by AREA admins. -- To be given out to Tournament Directors. -- To be given out to AREA participants (those that are ratable). -- To be used for blind forwarding. -- To be used for confirmation requests. -- pcode is the internal code for a privacy type. -- pid is the external code for a privacy type. -- descr is the description of the privacy type. create table privacy ( pcode serial primary key, pid text unique not null constraint bad_pid check (pid ~ '^[A-Z]+$'), descr text not null constraint bad_char_in_descr check (descr ~ '^[\041-\176]+( [\041-\176]+)*$') ); grant select, insert, update, delete on privacy to group area_admin; grant select on privacy to public; -- user_privacy -- This table defines what privacy access database users have. -- Restricted views of data will use the current user name (from the database -- connection) to control access to contact data. -- For some things more general access should also be indicated. For example, -- for locations, web publishing should imply that it is OK to give it to other -- AREA members. However, things that allow for outside automation, this -- shouldn't be done. For example, web publishing shouldn't imply blind -- forwarding for email addresses. -- username is a database user name (ultimately from pg_shadow). -- pcode is a type of allowed use of contact information. create table user_privacy ( username name, pcode int4 references privacy, primary key (username, pcode) ); -- entity_type -- This table defines valid entity types and indicates which ones can have -- AREA ratings. Initially I plan to define types for people, games that -- can beat their players, companies and clubs (gamer groups). -- etcode is the unique internal code for referencing entity types. -- etid is the unique external code for referencing entity types. -- descr is a description of the entity tpye. -- ratable is true if entities of this type can have AREA Ratings. -- The primary key definition is used to keep ratable from being -- changed after entities have been assigned an entity type. create table entity_type ( etcode serial primary key, etid text unique not null constraint bad_etid check (etid ~ '^[A-Z]+$'), descr text not null constraint bad_char_in_descr check (descr ~ '^[\041-\176]+( [\041-\176]+)*$'), ratable boolean not null, unique (etcode, ratable) ); grant select, insert, update, delete on entity_type to group area_admin; grant select on entity_type to public; -- genlabs -- This table defines valid alternate (not roman numerals) labels for -- generation label. Initially Sr -> 1 and Jr -> 2 will be defined. -- genlab is the label (e.g. Sr or Jr) -- gen is the generation number create table genlabs ( genlab text constraint bad_genlab check (genlab ~ '^[\041-\176]+( [\041-\176]+)*$'), gen int4 constraint bad_generation check (gen > 0 and gen < 4000), primary key (genlab, gen) ); grant select, insert, update, delete on genlabs to group area_admin; grant select on genlabs to public; -- This stuff is pretty constant so load it at database creation copy genlabs from stdin using delimiters ','; Sr,1 Jr,2 \. -- entity -- This table has an entry for anything that might get an AREA rating -- or have contact information. This includes people, games that can -- win, companies and clubs. -- entity is a unique internal code for referencing an entity. -- current_areaid is the current AREA ID in use by this person. -- current_name is the code for the entity's current name. -- etcode is the code for what kind of entity they are. -- rateable is whether this entity can be rated. -- admin_lock is used to restrict changes to the entities data to just admins. -- Typically after some kind of abuse or the entity's death. Changes can -- still be requested through automated interfaces, but they can only be -- applied after admin approval. -- created is when the entity record was first created. This won't be too -- accurate for old people as we haven't tracked that information previously. -- The foreign key (entity, current_areaid) makes sure that there is an -- AREA ID - entity pair for this entity and that it points back to it. -- This constraint is added after entity_areaid is created. -- The foreign key (current_name, entity) makes sure there is a name entry -- for this entity and that it points back to it. -- The foreign key (etcode, ratable) makes sure that the ratablility of -- an entity type can't change while entities are using it. create table entity ( entity serial primary key, current_areaid text unique not null, current_name int4 unique not null, etcode int4 not null, ratable boolean not null, admin_lock boolean not null, created timestamp default current_timestamp not null constraint future check(created <= current_timestamp), foreign key (etcode, ratable) references entity_type (etcode, ratable) ); grant select, insert, update, delete on entity to group area_admin; -- entity_areaid -- This table tracks all AREA IDs ever (officially) used by an entity. -- The constraints don't prevent someone from reusing an old AREA ID, -- but applications should require an AREA admin not to reuse an old ID -- as this is likely to cause confusion. Exactly one AREA ID must -- be current for each entity. -- entity is the entity code for the entity that is or was using the AREA ID. -- areaid is the AREA ID. Until all current AREA IDs use the new format, the -- format checking will be liberal enough to allow all previously assigned -- AREA IDs. Afterwards a check involving 'ended' can make sure current ones -- follow the new standard. Until then the new standard will be enforced in -- applications. -- started is when the AREA ID was assigned to the entity. -- ended is when the entity was no longer using this AREA ID. create table entity_areaid ( entity int4 not null references entity, areaid text not null constraint bad_areaid check (areaid ~ '^[A-Z0-9]+(\\.[0-9]{2,3})?$') constraint trailing_all_zeros check (areaid !~ '\\.0+?$') constraint missing_lead_zeros check (areaid !~ '^[0-9]{1,4}(\\.[0-9]+)?$'), started timestamp default current_timestamp not null constraint future check(started <= current_timestamp), ended timestamp constraint ea_bad_range check (ended > started) constraint future check(ended <= current_timestamp), primary key (entity, areaid) ); grant select, insert, update, delete on entity_areaid to group area_admin; -- In case we need to look up which entities used an AREA ID we want an -- index on areaid. create index entity_areaid_areaid on entity_areaid (areaid); -- Because entity and entity_areaid refer to each other, one constraint -- needs to be added later and needs to be deferrable. alter table entity add foreign key (entity, current_areaid) references entity_areaid (entity, areaid) deferrable; -- entity_name -- This table contains the various names that have been used by an entity. -- This generally shouldn't include typos. Typos should just get fixed. -- Adding or changing an alternate name should also generally not result in -- a new entry. New entries should mainly be made for legal name changes. This -- way we won't forget about old names when looking at historical data. -- Exactly one name must be current for a given entity. -- Names are currently restricted to the English alphabet plus some limited -- use of special characters. No accented characters are available. -- I don't think indexes for names will be very useful. They won't be used -- often, they will be accessed through a privacy view, they may be accessd -- lower cased or with partial matches. There currently aren't enough names -- for searching to be a big deal. If that changes a functional, partial -- index can be created (and tested to make sure it really gets used). -- This table should not be directly accessible except to AREA admins. -- entity is the entity to which this name applies. -- encode is a unique code for this entity that is useful for making sure -- only one name is current and allowing typos to be more easily fixed. -- lname is a person's last (or only) name(s). -- alname is an altenate last name. (Typically a maiden name.) -- fmname is a person's first and middle names if any. In some cases this -- might just be initials. -- aname is an alternate name that the person likes to be called. It might -- be a nickname or a short version of their first name. -- gen is their generation number. For the normal case, people should have -- no generation rather than a generation of 1. -- genlab is an alternate label to be used for displaying a person's -- generation. Typically Sr or Jr. If there is no genlab label, then -- roman numerals are used. -- started is when AREA became aware of the entity using this name. -- ended is when AREA became aware that this name was not to be used. -- descr is for admin use. Typically it would indicate why an old name changed. create table entity_name ( entity int4 not null references entity, encode serial primary key, lname text not null constraint bad_last_name check (lname ~ '^[A-Za-z]+(( |\'|-)[A-Za-z]+)*$'), alname text constraint bad_alt_last_name check (lname ~ '^[A-Za-z]+(( |\'|-)[A-Za-z]+)*$'), fmname text constraint bad_first_or_mid_name check (fmname ~ '^[A-Za-z]+(( |\'|-)[A-Za-z]+)*$'), aname text constraint bad_alt_name check (aname ~ '^[A-Za-z]+(( |\'|-)[A-Za-z]+)*$'), gen int4 constraint bad_generation check (gen > 0 and gen < 4000), genlab text constraint missing_gen check (genlab is null or gen is not null), started timestamp default current_timestamp not null constraint future check(started <= current_timestamp), ended timestamp constraint en_bad_range check (ended > started) constraint future check(ended <= current_timestamp), descr text constraint bad_char_in_descr check (descr ~ '^[\041-\176]+( [\041-\176]+)*$'), unique (entity, encode), foreign key (genlab, gen) references genlabs ); grant select, insert, update, delete on entity_name to group area_admin; -- Because entity and entity_name refer to each other, one constraint -- needs to be added later and needs to be deferrable. alter table entity add foreign key (entity, current_name) references entity_name (entity, encode) deferrable; -- entity_name_privacy -- This table specifies what kind of access is allowed for a name. -- The anticipated default for names is all uses are allowed. -- encode is the entity_name code. -- pcode is the privacy code. create table entity_name_privacy ( encode int4 references entity_name, pcode int4 references privacy, primary key (encode, pcode) ); grant select, insert, update, delete on entity_name_privacy to group area_admin; -- entity_phone -- Telephone number for an entity. -- The same phone number can be provided multiple times for the same entity, -- as there may be different comments provided with different privacy -- restrictions. -- entity is the entity code. -- epcode is key for this phone number. -- cc is the country code. For the US (or any country covered by the NANP) -- this is 1. -- area is the area or city code. This is optional for some countries but should -- be three digits if the country code is 1. -- local is the local number. This should be seven digits if the country code -- is 1. -- ext is an extension. -- descr is a comment about using the phone number. -- touched is when this record was last updated. create table entity_phone ( entity int4 not null references entity, epcode serial primary key, cc text not null constraint bad_cc check (cc ~ '^[0-9]+$'), area text constraint bad_area check (area ~ '^[0-9]+$'), local text not null constraint bad_local check (local ~ '^[0-9]+$'), ext text constraint bad_ext check (ext ~ '^[0-9]+$'), descr text constraint bad_char_in_descr check (descr ~ '^[\041-\176]+( [\041-\176]+)*$'), touched timestamp not null constraint future check(touched <= current_timestamp), constraint no_900 check (cc <> '1' or (area <> '900' and area <> '976')), constraint nanp check (cc <> '1' or (area is not null and length(area) = 3 and length(local) = 7)) ); grant select, insert, update, delete on entity_phone to group area_admin; -- entity_phone_privacy -- This table defines what kind of access is allowed for a phone number. -- The anticipated default is that it may not be given out. -- epcode is the entity phone code. -- pcode is the privacy code. create table entity_phone_privacy ( epcode int4 references entity_phone, pcode int4 references privacy, primary key (epcode, pcode) ); grant select, insert, update, delete on entity_phone_privacy to group area_admin; -- entity_email -- Email address for an entity. -- The same email address can be provided multiple times for the same entity, -- as there may be different comments provided with different privacy -- restrictions. -- The applications should probably warn people about oddball, but legal -- email addresses. -- We aren't going to accept domain literals as those are only to be used -- in emergencies to work around something that is broken. -- entity is the entity code. -- eecode is key for this email address. -- local is the local part of the email address (not RFC 821 encoded). -- domain is the lowercased domain name. -- descr is a comment about using the email address. -- touched is when this record was last updated. create table entity_email ( entity int4 not null references entity, eecode serial primary key, local text not null constraint bad_local check (local ~ '^[\040-\176]+$'), domain text not null constraint bad_domain check (domain ~ '^[a-z0-9][-a-z0-9]*[a-z0-9](\.[a-z0-9][-a-z0-9]*[a-z0-9])+$'), descr text constraint bad_char_in_descr check (descr ~ '^[\041-\176]+( [\041-\176]+)*$'), touched timestamp not null constraint future check(touched <= current_timestamp) ); grant select, insert, update, delete on entity_email to group area_admin; -- Just in case we want to look people up by email address or domain (which -- has been normalized) create an index. create index entity_email_address on entity_email (domain, local); -- entity_email_privacy -- This table defines what kind of access is allowed for an email address. -- The anticipated default is that it may be used to confirm requests. -- eecode is the entity email address. -- pcode is the privacy code. create table entity_email_privacy ( eecode int4 references entity_email, pcode int4 references privacy, primary key (eecode, pcode) ); grant select, insert, update, delete on entity_email_privacy to group area_admin; -- entity_url -- URL for an entity. -- The same URL can be provided multiple times for the same entity, -- as there may be different comments provided with different privacy -- restrictions. -- Only http or https URLs are allowed. No usernames or passwords are allowed. -- entity is the entity code. -- eucode is key for this URL. -- url is the urlencoded URL. Even though browsers may encode stuff (e.g. ~) as -- necessary we will force anything not allowed to be encoded. We can't do -- the encoding ourselves because we need context to do that. -- descr is a comment about using the URL. -- touched is when this record was last updated. create table entity_url ( entity int4 not null references entity, eucode serial primary key, url text not null constraint bad_url check (url ~ '^[hH][tT][tT][pP][sS]?://[a-zA-Z0-9][-a-zA-Z0-9]*[a-zA-Z0-9](\\.[a-zA-Z0-9][-a-zA-Z0-9]*[a-zA-Z0-9])+(:[0-9]+)?(/([a-zA-Z0-9$_.+!*\'(),/;:@&=]|%[0-9a-fA-F][0-9a-fA-F])*(\\?([a-zA-Z0-9$_.+!*\'(),/;:@&=]|%[0-9a-fA-F][0-9a-fA-F])*)?)?$'), descr text constraint bad_char_in_descr check (descr ~ '^[\041-\176]+( [\041-\176]+)*$'), touched timestamp not null constraint future check(touched <= current_timestamp) ); grant select, insert, update, delete on entity_url to group area_admin; -- entity_url_privacy -- This table defines what kind of access is allowed for a URL. -- The anticipated default is that it may be used for any purpose. -- eucode is the entity URL. -- pcode is the privacy code. create table entity_url_privacy ( eucode int4 references entity_url, pcode int4 references privacy, primary key (eucode, pcode) ); grant select, insert, update, delete on entity_url_privacy to group area_admin; -- entity_postal -- Postal address for an entity. -- The same postal address can be provided multiple times for the same entity, -- as there may be different comments provided with different privacy -- restrictions. -- This will be treated as opaque. It is up to the members to make sure -- their address is usable. We should remind them to include postal code -- and country. They shouldn't include their name in the address. If they -- have special instructions for using the address (like using someone -- else's name instead of theirs) that should go in the description. -- entity is the entity code. -- emcode is key for this postal address. -- address is the postal address. It may (and normally will) have multiple -- lines. -- descr is a comment about using the URL. -- touched is when this record was last updated. create table entity_postal ( entity int4 not null references entity, emcode serial primary key, address text not null constraint bad_address check (address ~ '^[\041-\176]+( [\041-\176]+)*(\n[\041-\176]+( [\041-\176]+)*)*$'), descr text constraint bad_char_in_descr check (descr ~ '^[\041-\176]+( [\041-\176]+)*$'), touched timestamp not null constraint future check(touched <= current_timestamp) ); grant select, insert, update, delete on entity_postal to group area_admin; -- entity_postal_privacy -- This table defines what kind of access is allowed for a postal address. -- The anticipated default is that it may be used by members and tournament -- directors. -- epcode is the entity postal address. -- pcode is the privacy code. create table entity_postal_privacy ( emcode int4 references entity_postal, pcode int4 references privacy, primary key (emcode, pcode) ); grant select, insert, update, delete on entity_postal_privacy to group area_admin; -- entity_location -- The location of an entity on the surface of the Earth. -- The same location can be provided multiple times for the same -- entity, as there may be different comments provided with different privacy -- restrictions. -- If someone doesn't want to provide exact coordinates for their location, -- then it is suggested that they either give them for a nearby landmark or -- round them off and note that in the description. That way searches for -- nearby players will still work. People will normally give location in -- latitude and longitude in fractional degrees. Internally this will be -- converted to a retangular cooridate data type (cube). -- Until check constraints are supported in domains, we need to have them here. -- entity is the entity code. -- elcode is key for this location. -- location specifies the location on the surface of the earth -- descr is a comment about using the location. -- touched is when this record was last updated. create table entity_location ( entity int4 not null references entity, elcode serial primary key, location earth not null constraint not_point check(is_point(location)) constraint not_3d check(cube_dim(location) <= 3) constraint on_surface check(abs(cube_distance(location,'(0)'::cube) / earth() - 1) < '10e-12'::float8); descr text constraint bad_char_in_descr check (descr ~ '^[\041-\176]+( [\041-\176]+)*$'), touched timestamp not null constraint future check(touched <= current_timestamp) ); grant select, insert, update, delete on entity_location to group area_admin; -- This index should allow for efficient checks of containment in cubes -- A great circle distance can be easily changed into a secant distance -- used for a bounding box, though the secant distance should be checked -- on the returned locations. create index entity_cube on entity_location using gist (location); -- entity_location_privacy -- This table defines what kind of access is allowed for a location. -- The anticipated default is that it may be used by members and tournament -- directors. -- elcode is the entity location. -- pcode is the privacy code. create table entity_location_privacy ( elcode int4 references entity_location, pcode int4 references privacy, primary key (elcode, pcode) ); grant select, insert, update, delete on entity_location_privacy to group area_admin; -- entity_admin_note -- This table has notes about the entity added by AREA admins. They might -- be used for such things as noting abuse incidents or why an administrative -- lock has been applied to an entity. These are always restricted to AREA -- admins. -- entity is the entity code -- eacode is the code for this note. -- descr is the note -- started is when the note was created. -- ended is when the note was superceded or ceased to be applicable. create table entity_admin_note ( entity int4 not null references entity, eacode serial primary key, descr text not null constraint bad_char_in_descr check (descr ~ '^[\041-\176]+( [\041-\176]+)*$'), started timestamp not null constraint future check(started <= current_timestamp), ended timestamp constraint en_bad_range check (ended > started) constraint future check(ended <= current_timestamp) ); grant select, insert, update, delete on entity_admin_note to group area_admin; -- entity_view -- Privacy restricted view of entity. -- entity is the unique entity code -- current_areaid is the current AREA ID -- lname is the last name if available -- alname is an alternate last name -- fmname is the first and middle names if available -- aname is an alternate name if available -- gen is the generation number if available -- genlab is the generation label if available -- etcode is the entity type code for this entity -- ratable is whether or not this entity can have game ratings create view entity_view (entity, current_areaid, lname, alname, fmname, aname, gen, genlab, etcode, ratable) as select entity.entity, current_areaid, lname, alname, fmname, aname, gen, genlab, etcode, ratable from entity left join (select lname, alname, fmname, aname, gen, genlab, encode from entity_name where exists (select 1 from user_privacy join entity_name_privacy using (pcode) where user_privacy.username = current_user and entity_name_privacy.encode = entity_name.encode)) as name on (entity.current_name = name.encode); grant select on entity_view to public; -- entity_name_view -- Privacy restricted view of entity_name -- entity is the unique entity code -- lname is the last name -- alname is an alternate last name -- fmname is the first and middle names -- aname is an alternate name -- gen is the generation number -- genlab is the generation label -- current is whether or not this name is current create view entity_name_view as select entity.entity, lname, alname, fmname, aname, gen, genlab, entity.current_name = entity_name.entity as current from entity_name, entity where entity.entity = entity_name.entity and exists (select 1 from user_privacy join entity_name_privacy using (pcode) where user_privacy.username = current_user and entity_name_privacy.encode = entity_name.encode); grant select on entity_name_view to public; -- entity_phone_view -- Privacy restricted view of entity_phone -- entity is the unique entity code -- cc is the country code -- area is the area code -- local is the local number -- ext is the extension -- descr has a usage comment create view entity_phone_view as select entity, cc, area, local, ext, descr from entity_phone where exists (select 1 from user_privacy join entity_phone_privacy using (pcode) where user_privacy.username = current_user and entity_phone_privacy.epcode = entity_phone.epcode); grant select on entity_phone_view to public; -- entity_email_view -- Privacy restricted view of entity_email -- entity is the unique entity code -- local is the local part of the email address -- domain is the domain part of the email address -- descr has a usage comment create view entity_email_view as select entity, local, domain, descr from entity_email where exists (select 1 from user_privacy join entity_email_privacy using (pcode) where user_privacy.username = current_user and entity_email_privacy.eecode = entity_email.eecode); grant select on entity_email_view to public; -- entity_url_view -- Privacy restricted view of entity_url -- entity is the unique entity code -- url is the URL -- descr has a usage comment create view entity_url_view as select entity, url, descr from entity_url where exists (select 1 from user_privacy join entity_url_privacy using (pcode) where user_privacy.username = current_user and entity_url_privacy.eucode = entity_url.eucode); grant select on entity_url_view to public; -- entity_postal_view -- Privacy restricted view of entity_postal -- entity is the unique entity code -- address is the postal address -- descr has a usage comment create view entity_postal_view as select entity, address, descr from entity_postal where exists (select 1 from user_privacy join entity_postal_privacy using (pcode) where user_privacy.username = current_user and entity_postal_privacy.emcode = entity_postal.emcode); grant select on entity_postal_view to public; -- entity_location_view -- Privacy restricted view of entity_location -- entity is the unique entity code -- location specifies the location using rectangular coordinates -- descr has a usage comment create view entity_location_view as select entity, location, descr from entity_location where exists (select 1 from user_privacy join entity_location_privacy using (pcode) where user_privacy.username = current_user and entity_location_privacy.elcode = entity_location.elcode); grant select on entity_location_view to public; -- Old Schema definitions being converted follow. -- Publisher table -- This is used to provide consistant versions of publisher names and -- a single place to keep track of a URL for the publisher. -- publishers Table name -- pubid Internal code for a publisher -- pubname The name of the publisher -- puburl An optional URL for the publisher create table publishers ( pubid text primary key constraint bad_char_in_id check (pubid ~ '^[A-Z0-9]+$'), pubname text not null constraint bad_char_in_name check (pubname ~ '^[\041-\176]+( [\041-\176]+)*$'), puburl text constraint bad_char_in_url check (puburl ~ '^[\041-\176]+$') ); -- Allow access to it from the web server account grant select on publishers to public; -- Rating type table -- This table defines valid rating type codes and provides a text description -- rtype Rating type code (e.g. WTA, TEAM, RACE, TWO, etc.) -- descr A description of the rating type create table rtypes ( rtype text primary key constraint bad_char_in_rtype check (rtype ~ '^[A-Z0-9]+$'), descr text not null constraint bad_char_in_descr check (descr ~ '^[\041-\176]+( [\041-\176]+)*$') ); -- Allow access to it from the web server account grant select on rtypes to public; -- Contacts table -- This table defines valid contact addresses (mostly for reporting results) -- These are all public AREA email addresses -- contact Contact code -- email Email address create table contacts ( contact text primary key constraint bad_char_in_contact check (contact ~ '^[A-Z0-9]+$'), email text not null constraint bad_char_in_email check (email ~ '^[-_.a-zA-Z0-9]+@[-_.a-zA-Z0-9]+$') ); -- Allow access to it from the web server account grant select on contacts to public; -- Game definition table -- This is the primary definition for games. -- Titles may only contain printable US ASCII characters and -- imbedded spaces. Sorting will be done using the US ASCII colating -- sequence with uppercase letters treated as lowercase. -- games Table name -- gameid Initially will be excel sheet name -- title The game title -- rtype Rating type (e.g. WTA, RACE, TEAM or TWO) -- contact Where to send results (by email) -- touched Last time gameid, or title (not ratings) changed create table games ( gameid text primary key constraint bad_char_in_id check (gameid ~ '^[A-Z0-9]+$'), title text not null constraint bad_char_in_title check (title ~ '^[\041-\176]+( [\041-\176]+)*$'), rtype text not null constraint bad_rtype references rtypes, contact text not null constraint bad_contact references contacts, touched timestamp default 'now' not null ); -- This probably won't help searching, but should help displaying the -- sorted title index. create index title_idx on games (lower(title)); -- Allow access to it from the web server account grant select on games to public; -- Table of publishers for a game -- gamepubs Table name -- gameid Game being published -- pubid One of the game's publishers create table gamepubs ( gameid text constraint bad_gameid references games, pubid text constraint bad_pubid references publishers, primary key (gameid, pubid) ); -- Allow access to it from the web server account grant select on gamepubs to public; -- Table of wbc events (from any year, not just current) -- wbc Table name -- code A WBC code -- event The event title (may not always be known) -- url URL for the event page if any create table wbc ( code text primary key constraint bad_char_in_code check (code ~ '^[\041-\176]+$') constraint no_slash_in_code check (code !~ '/'), event text constraint bad_char_in_event check (event ~ '^[\041-\176]+( [\041-\176]+)*$'), url text constraint bad_char_in_url check (url ~ '^[\041-\176]+$') ); -- For matching searches wbc codes are case insensitive and will be done -- using lower case. create unique index wbc_lower on wbc (lower(code)); -- Allow access to it from the web server account grant select on wbc to public; -- Table of WBC codes for games -- There might be muliple entries for a single code or for a single game -- because WBC events don't map 1 to 1 to games. -- We can't have slashses (/) in the WBC code since we use the WBC code -- in generated URLs. Unescaped slashes break relative references and -- escaped ones are detected as not found before rewriting can catch -- the request. Setting the base in generated html documents is one -- possible work around if the WBC uses any in their codes. -- wbcgames Table name -- code WBC code from wbc table -- gameid gameid from games table create table wbcgames ( code text constraint bad_wbc_code references wbc, gameid text constraint bad_gameid references games, primary key (code, gameid) ); -- Allow access to it from the web server account grant select on wbcgames to public; -- Current AREA ratings -- Note this record should only be created for person - game pairs where -- either the person has at least one recorded rated game or has specifically -- notified AREA that they have an interest in the game. -- This table should be used to retrive data even though it isn't the -- ultimate source for data. It is too expensive to rederive this information -- from the base data. If something bad happens, this table should be -- rebuildable from a transaction table that includes actions for the -- results of rated games, expressing interest in a game, or making hand -- corrections to fix problems. -- crate Table name -- areaid From the cname table -- gameid From the games table -- rate Current AREA rating -- frq Number of times payed rated games of this game -- If frq is 0 the player has expressed interest in the game. -- opp Total number of different opponents played -- rmp Total number of rated games played remotely (PBM, PBEM, VASL, etc.) -- trn Total number of tournaments played in (with rated games) -- rp String indicating type of remote play -- gm String indciating when last gm'd -- touched Timestamp from when information in this record was changed -- Typically this should be the last time a match was entered -- for this person. create table crate ( areaid text constraint bad_areaid references cname, gameid text constraint bad_gameid references games, rate int4 default 5000 not null constraint rate_nonnegative check (rate >= 0), frq int4 default 0 not null constraint frq_nonnegative check (frq >= 0), opp int4 default 0 not null constraint opp_nonnegative check (opp >= 0), rmp int4 default 0 not null constraint rmp_nonnegative check (rmp >= 0), trn int4 default 0 not null constraint trn_nonnegative check (trn >= 0), rp text, gm text, touched timestamp default 'now' not null, primary key (areaid, gameid) ); -- Allow for fast access when searching by game. create index crate_game on crate (gameid, areaid); -- Allow access to it from the web server account grant select on crate to public; -- Related URL table -- This is used to have links to other web sites related to a game displayed. -- gameurls Table name -- gameid Game the link applies to -- url The url for the link -- comment Text describing the relation -- expires When to stop displaying the link create table gameurls ( gameid text constraint bad_gameid references games, url text constraint bad_char_in_url check (url ~ '^[\041-\176]+$'), comment text not null constraint bad_char_in_comment check (comment ~ '^[\041-\176]+( [\041-\176]+)*$'), expires timestamp default 'infinity' not null, primary key (gameid, url) ); -- Allow access to it from the web server account grant select on gameurls to public;