Separate location #12

Open
wants to merge 2 commits into
from

Conversation

Projects
None yet
2 participants
@cbbrowne
Contributor

cbbrowne commented Mar 7, 2012

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

cbbrowne added some commits Mar 6, 2012

Draw current_health out into separate table, ship_health. This is pro…
…bably not complete; future_health should also be drawn out, possibly to the same table.
@cbbrowne

This comment has been minimized.

Show comment
Hide comment
@cbbrowne

cbbrowne Mar 7, 2012

Owner

I would like to drop the location from the ship table, but that makes the trigger and rule definitions problematic to define.

I would like to drop the location from the ship table, but that makes the trigger and rule definitions problematic to define.

This comment has been minimized.

Show comment
Hide comment
@Abstrct

Abstrct Mar 7, 2012

The new location record would need to be inserted in the my_ships insert rule. Then, a trigger on ship_location would need to validate the chosen location.

The new location record would need to be inserted in the my_ships insert rule. Then, a trigger on ship_location would need to validate the chosen location.

@cbbrowne

This comment has been minimized.

Show comment
Hide comment
@cbbrowne

cbbrowne Mar 7, 2012

Owner

I expect that we'll eventually want to put all of the motion-related attributes here. Location vector, motion vector, perhaps eventually burn vector.

Fuel, too.

I expect that we'll eventually want to put all of the motion-related attributes here. Location vector, motion vector, perhaps eventually burn vector.

Fuel, too.

This comment has been minimized.

Show comment
Hide comment
@Abstrct

Abstrct Mar 7, 2012

MOVE_SHIPS() is going to need to update location, speed and direction. So those are the columns I would assume we want to be together. Target_speed, target_direction and destination are all user updatable so they would be best in their own table (ship_control). This should allow MOVE_SHIPS() and SHIP_COURSE_CONTROL() to be run at the same time without deadlocking.

MOVE_SHIPS() is going to need to update location, speed and direction. So those are the columns I would assume we want to be together. Target_speed, target_direction and destination are all user updatable so they would be best in their own table (ship_control). This should allow MOVE_SHIPS() and SHIP_COURSE_CONTROL() to be run at the same time without deadlocking.

@cbbrowne

This comment has been minimized.

Show comment
Hide comment
@cbbrowne

cbbrowne Mar 7, 2012

Owner

I wonder if it is the right thing to "insert to my_ships."

It seems to me that this will require increasing amounts of cleverness as attributes get added.

I'm finding I want to do multiple inserts (e.g. - need INSERT INTO ship(), INSERT INTO ship_location (), possibly more...), which doesn't seem to work very well.

Probably what has to happen is for this to be refactored into some function calls.

Thus, something more like:

CREATE OR REPLACE RULE ship_insert AS ON INSERT TO my_ships DO INSTEAD
perform create_ship (parameters);

Suppose create_ship() returns the new ship ID, then we want...

perform locate_ship(create_ship(parameters), location);

That works if the ID is only used once. If there turn out to be two functions that require the ship ID, then it all has to get wrapped together. Perhaps that simply means that create_ship() does everything, and maybe there's no need for a trigger on ship.

I wonder if it is the right thing to "insert to my_ships."

It seems to me that this will require increasing amounts of cleverness as attributes get added.

I'm finding I want to do multiple inserts (e.g. - need INSERT INTO ship(), INSERT INTO ship_location (), possibly more...), which doesn't seem to work very well.

Probably what has to happen is for this to be refactored into some function calls.

Thus, something more like:

CREATE OR REPLACE RULE ship_insert AS ON INSERT TO my_ships DO INSTEAD
perform create_ship (parameters);

Suppose create_ship() returns the new ship ID, then we want...

perform locate_ship(create_ship(parameters), location);

That works if the ID is only used once. If there turn out to be two functions that require the ship ID, then it all has to get wrapped together. Perhaps that simply means that create_ship() does everything, and maybe there's no need for a trigger on ship.

This comment has been minimized.

Show comment
Hide comment
@Abstrct

Abstrct Mar 7, 2012

Hmm, good points about the ship's ID. I am going to have to play around with this and see if we can find a reliable way of tossing the ID around between tables or storing the initial location somewhere in a column like.. initial_location or which planet the ship originated from (this may limit future development though if ships can one day be created at somewhere that isn't a planet).

Hmm, good points about the ship's ID. I am going to have to play around with this and see if we can find a reliable way of tossing the ID around between tables or storing the initial location somewhere in a column like.. initial_location or which planet the ship originated from (this may limit future development though if ships can one day be created at somewhere that isn't a planet).

This comment has been minimized.

Show comment
Hide comment
@cbbrowne

cbbrowne Mar 7, 2012

Owner

Well, the value of the ID is in currval('whatever-is-the-sequence'), so it's referenceable, as long as the trigger/rule does so after the ship is inserted.

Owner

cbbrowne replied Mar 7, 2012

Well, the value of the ID is in currval('whatever-is-the-sequence'), so it's referenceable, as long as the trigger/rule does so after the ship is inserted.

@Abstrct

This comment has been minimized.

Show comment
Hide comment
@Abstrct

Abstrct Mar 7, 2012

Owner

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

Owner

Abstrct commented Mar 7, 2012

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

This comment has been minimized.

Show comment
Hide comment
@cbbrowne

cbbrowne Mar 8, 2012

Contributor

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.)

  • select when from transaction where id = currval('tx');

"Oh, who's the user?"

  • select who from transaction where id = currval('tx');

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() :-).

Contributor

cbbrowne commented Mar 8, 2012

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.)

  • select when from transaction where id = currval('tx');

"Oh, who's the user?"

  • select who from transaction where id = currval('tx');

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() :-).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment