-- -- Classified Ads data-model.sql -- -- Created July 12, 1996 by Philip Greenspun (philg@mit.edu) -- -- added auction stuff on December 21, 1996 -- -- converted from Illustra to Oracle January 5, 1998 -- -- edited to run from generic community system users table -- (instead of email address/name stored in row) teadams@mit.eud April 2, 1998 -- edited by philg on 11/18/98 to incorporate employment ad fields -- and also domain_type -- edited by teadams@mit.edu on 1/7/98 to add active_p to ad_domains -- edited by teadams@mit.edu on 2/10/98 to prevent multiple seed inserts into -- classified_alerts_last_updates -- edited by curtisg@arsdigita.com on 3/9/00 to convert primary keys -- to integers create table ad_domains ( domain_id integer primary key, -- short key, e.g., "Jobs" domain varchar(30) unique, -- a description for this domain, e.g., "Jobs classifieds" -- or "Job Listings", this is designed to serve as a -- hypertext anchor back to the top-level page full_noun varchar(100), primary_maintainer_id integer not null references users(user_id), domain_type varchar(30), -- e.g., 'employment', 'automotive' blurb varchar(4000), blurb_bottom varchar(4000), insert_form_fragments varchar(4000), ad_deletion_blurb varchar(4000), default_expiration_days integer default 100, levels_of_categorization integer default 1, user_extensible_cats_p char(1) default 'f' check(user_extensible_cats_p in ('t','f')), wtb_common_p char(1) default 'f' check(wtb_common_p in ('t','f')), auction_p char(1) default 'f' check(auction_p in ('t','f')), geocentric_p char(1) default 'f' check(geocentric_p in ('t','f')), --should this show up on the user interface? active_p char(1) default 't' check (active_p in ('t','f')) ); create sequence ad_domain_id_seq start 1; -- we test these on inserts or updates to the table -- with user interface complaints --- check_code is something that goes into a Tcl If statement create table ad_integrity_checks ( integrity_check_id integer primary key, domain_id integer references ad_domains(domain_id), check_code varchar(4000), error_message varchar(4000) ); create sequence ad_integrity_check_id_seq start 1; -- -- We have a lot of redundant info in this -- (e.g., each primary_category may be represented 50 times) -- but we query into this with DISTINCT and we memo-ize -- so we don't care -- -- the entire user interface is built from this -- create table ad_categories ( category_id integer primary key, domain_id integer references ad_domains(domain_id), primary_category varchar(100), subcategory_1 varchar(100), subcategory_2 varchar(100), ad_placement_blurb varchar(4000) ); create sequence ad_category_id_seq start 1; -- if we're going to have a system where we only use primary -- category then presumably these should be constrained unique -- we can do that with an index: create unique index ad_categories_unique on ad_categories ( domain_id, primary_category ); -- old system had about 10,000 ads so far, this way we'll know whether -- or not an ad was inserted under the Oracle regime create sequence classified_ad_id_sequence; create table classified_ads ( classified_ad_id integer primary key, user_id integer not null references users, domain_id integer not null references ad_domains(domain_id), originating_ip varchar(16), -- stored as string, separated by periods posted datetime not null, expires datetime, wanted_p char(1) default 'f' check(wanted_p in ('t','f')), private_p char(1) default 't' check(private_p in ('t','f')), -- if 'f', the reply_to link will not be displayed with the ad reply_to_poster_p char(1) default 't' check(reply_to_poster_p in ('t','f')), primary_category varchar(100), subcategory_1 varchar(100), subcategory_2 varchar(100), manufacturer varchar(50), model varchar(50), date_produced datetime, item_size varchar(100), color varchar(50), location varchar(200), us_citizen_p char(1) default 'f' check(us_citizen_p in ('t','f')), one_line varchar(150), full_ad varchar(3600), -- is the ad in HTML or plain text (the default) html_p char(1) default 'f' check(html_p in ('t','f')), graphic_url varchar(200), price numeric(9,2), currency varchar(50) default 'US dollars', auction_p char(1) default 't' check(auction_p in ('t','f')), country varchar(2), state varchar(30), -- when system is used for employment ads (Cognet wanted these) employer varchar(100), salary_range varchar(200), last_modified datetime ); create function trig_classified_update_last_mod() returns opaque as ' declare begin NEW.last_modified := current_timestamp; IF TG_OP=''INSERT'' and NEW.posted is null THEN NEW.posted := current_timestamp; END IF; RETURN NEW; end; ' language 'plpgsql'; create trigger classified_update_last_mod before insert or update on classified_ads for each row execute procedure trig_classified_update_last_mod(); create index classified_ads_by_primary_cat on classified_ads (primary_category); create index classified_ads_by_subcat_1 on classified_ads (subcategory_1); -- for the "remember to update your ads spam" create index classified_ads_by_email on classified_ads (user_id); -- the auction system create table classified_auction_bids ( bid_id integer primary key, classified_ad_id integer not null references classified_ads, user_id integer not null references users, bid numeric(9,2), currency varchar(100) default 'US dollars', bid_time datetime, location varchar(100) ); create sequence classified_auction_bid_id_seq start 1; create index classified_auction_bids_index on classified_auction_bids (classified_ad_id); -- audit table (we hold deletions, big changes, here) -- warning: this gives SQL*Plus heartburn if typed at the shell create table classified_ads_audit ( classified_ad_id integer, user_id integer, domain_id integer, originating_ip varchar(16), posted datetime, expires datetime, wanted_p char(1), private_p char(1), reply_to_poster_p char(1), primary_category varchar(100), subcategory_1 varchar(100), subcategory_2 varchar(100), manufacturer varchar(50), model varchar(50), date_produced datetime, item_size varchar(100), color varchar(50), location varchar(200), us_citizen_p char(1), one_line varchar(150), full_ad varchar(3600), html_p char(1), graphic_url varchar(200), price numeric(9,2), currency varchar(50), auction_p char(1), country varchar(2), state varchar(30), employer varchar(100), salary_range varchar(200), last_modified datetime, -- from where user edited ad audit_ip varchar(16), -- deleted by moderator? deleted_by_admin_p char(1) default 'f' check(deleted_by_admin_p in ('t','f')) ); create index classified_ads_audit_idx on classified_ads_audit(classified_ad_id); create index classified_ads_audit_user_idx on classified_ads_audit(user_id); -- ConText index stuff -- this is also good for sequential scanning with pseudo_contains create view classified_context_view as select ca.classified_ad_id, ca.domain_id, ca.one_line, ca.expires, ca.one_line || ' ' || ca.full_ad || ' ' || u.email || ' ' || u.first_names || ' ' || u.last_name || ' ' || ca.manufacturer || ' ' || ca.model || ' ' as indexed_stuff from classified_ads ca, users u where ca.user_id = u.user_id; -- email alert system -- -- this holds the last time we sent out notices -- create table classified_alerts_last_updates ( update_id integer primary key, weekly datetime, weekly_total integer, daily datetime, daily_total integer, monthu datetime, monthu_total integer ); create function init_classifieds() returns boolean as ' declare n_last_update_seed_rows integer; begin select count(*) into n_last_update_seed_rows from classified_alerts_last_updates; if n_last_update_seed_rows = 0 then insert into classified_alerts_last_updates (update_id, weekly, weekly_total, daily, daily_total, monthu, monthu_total) values (1, current_timestamp,0,current_timestamp,0,current_timestamp,0); end if; return ''t''; end; ' language 'plpgsql'; select init_classifieds(); create table classified_email_alerts ( alert_id integer primary key, domain_id integer not null references ad_domains(domain_id), user_id integer not null references users, valid_p char(1) default 't' check(valid_p in ('t','f')), expires datetime, howmuch varchar(100), -- 'everything', 'one_line' frequency varchar(100), -- 'instant', 'daily', 'Monday/Thursday', 'weekly', etc. alert_type varchar(20), -- 'all', 'category', 'keywords' category varchar(100), keywords varchar(100), established datetime ); create sequence classified_email_alert_id_seq start 1; create function trig_classified_ed_established() returns opaque as ' declare begin IF NEW.established IS NULL THEN NEW.established := current_timestamp; END IF; RETURN NEW; end; ' language 'plpgsql'; create trigger classified_ea_established before insert on classified_email_alerts for each row execute procedure trig_classified_ed_established(); --- random stuff for the AOLserver /NS/Admin pages