Abstrct / Schemaverse

The Schemaverse is a space-based strategy game implemented entirely within a PostgreSQL database. Compete against other players using raw SQL commands to command your fleet. Or, if your PL/pgSQL-foo is strong, wield it to write AI and have your fleet command itself!
schemaverse.com
PostgreSQL License
356 stars 39 forks source link

Separate location #12

Open cbbrowne opened 12 years ago

cbbrowne commented 12 years ago

Here is a "drafty" form of drawing location off of the main ship table to a separate ship_location table.

Abstrct commented 12 years ago

I was a bit worried about currval(seq) due to the way ID's are handled in the game but I just gave some code a go to test it and there were no complications. There is no reason why we cannot trust currval('ship_id_seq) in the insert into the ship_location table during the my_ships view insert rule.

CREATE SEQUENCE s_seq INCREMENT 1 MINVALUE 1 MAXVALUE 9223372036854775807 START 1 CACHE 1;

create table s ( id integer, val integer ); create table s_l ( id integer, val integer ); create view s_v as select s.id, s.val sval, s_l.val as slval FROM s, s_l WHERE s.id=s_l.id;

CREATE OR REPLACE RULE s_insert AS ON INSERT TO s_v DO INSTEAD ( INSERT INTO s(val) VALUES(NEW.sval); INSERT INTO s_l VALUES(currval('s_seq'), NEW.slval); ) ;

CREATE OR REPLACE FUNCTION id_dealer() RETURNS trigger AS $BODY$ BEGIN NEW.id = nextval('s_seq');

RETURN NEW; END $BODY$ LANGUAGE plpgsql VOLATILE SECURITY DEFINER COST 100;

CREATE TRIGGER d_dealer BEFORE INSERT OR UPDATE ON s FOR EACH ROW EXECUTE PROCEDURE id_dealer();

-- Run each of these in a different process INSERT INTO s_v(slval, sval) SELECT 1,1 from generate_series(1,1000000); INSERT INTO s_v(slval, sval) SELECT 2,2 from generate_series(1,1000000); INSERT INTO s_v(slval, sval) SELECT 3,3 from generate_series(1,1000000);

--Check to missmatched results select * from s_v where slval <> sval -- No Results were returned

cbbrowne commented 12 years ago

There is an alternate perspective of "currval" which involves the function returning the most recently generated sequence value from ANY sequence associated with your DB connection.

Which is perhaps the most terrible behavior possible; it means that if you decided to (say) replicate Schemaverse using Slony or Londiste, you might instead capture sequence values being used as part of the internals of those replication systems. Horrible, horrible, horrible.

(Poking at docs...) Ah, the function that does this is lastval(). http://www.postgresql.org/docs/9.1/static/functions-sequence.html You'd have to be insane and stupid to use lastval() for anything.

But if you use currval('specific_seq_name'), it's all good.

A couple years ago, I was working on an experimental domain registry prototype where we were using currval() extremely heavily to establish transaction contexts. Basically, we'd create a logical transaction: insert into transaction (id, when, who) values (nextval('tx'), now(), 'my-user-name');

and then, throughout the rest of the DB activity, HEAVY use was made of currval('tx') to reference the transaction context data.

"Oh, what time are we using for this transaction?" (It didn't have to be NOW() - it was meaningful to backdate/forward date activity.)

"Oh, who's the user?"

We'd attach all kinds of additional data to the transaction by joining in extra tables; the key to getting at it was always currval('tx'). And this worked out AOK. I have a fair bit of faith in currval() :-).