Question: Generally, How does one tell SQLAlchemy that a table is read-only (via DB permissions) so it doesn't try to do things to it that table implicitly that require more then select permission?
Or asked another way, How does one tell SQLAlchemy that a first table (say States) is read only because of DB level permissions, so that SQLAlchemy does not emit "...FOR SHARE..." locking on that table (States) when it is inserting data into a different table (say Users) that has a foreign key reference to the first read only table (States)? Details: I have a apache/python/pylons/sqlalchemy/ webapp system with many tables with differing levels of permission on them across many users. There are a number of table that are readonly to all users or to certain users because of DB permissions. When certain SA operations are run on tables that has the readonly tables as foreign keys bad things happen. This is a simplified example to illustrate the problem. (Please forgive syntax related typos that may be present below.) Using Postgresql 8.4 DBMS, make a new db called "test", in the "public" schema, create some tables, say: (A) table "Users" with fields: user_id (primary key), user_name, state_id (foreign key to state table state_id column) (B) table "States" with fields: state_id (primary key), state_name -- populate the States table with the 50 states via insert queries (or just do 2 the number of states doesn't effect the outcome) -- create some group roles (not login roles) CREATE ROLE ro_owner NOSUPERUSER INHERIT NOCREATEDB NOCREATEROLE; CREATE ROLE rw_owner NOSUPERUSER INHERIT NOCREATEDB NOCREATEROLE; CREATE ROLE webuser LOGIN PASSWORD 'password' NOSUPERUSER INHERIT NOCREATEDB NOCREATEROLE; -- Change owners and lock down the DB to prevent certain DB level users from editing things they shouldn't (rw_user and ro_user are group roles (not pg login roles)): ALTER TABLE Users OWNER TO rw_owner; REVOKE ALL on Users from webuser; REVOKE ALL on Users from public; GRANT ALL on Users to webuser; ALTER TABLE States OWNER TO ro_owner; REVOKE ALL on States from webuser; REVOKE ALL on States from public; GRANT SELECT on States to webuser; -- create sqlalchemy Tables and Class for the above tables called users_table, states_table, Users, and States respectively user_table = Table('users', metadata, Column('user_id', Integer, primary_key=True), Column('user_name', Unicode(255), nullable = False), Column('state_id', Integer, ForeignKey('states.id'), nullable = False) ) class Users(Base): pass state_table = Table('states', metadata, Column('state_id', Integer, primary_key=True), Column('state_name', Unicode(255), nullable = False), ) class State(Base): pass -- map them mapper(User, user_table, properties = { 'state' : relation(State, primaryjoin = (user_table.c.state_id == state_table.c.state_id), uselist = False) }) mapper(State, state_table) -- connect to the DB as the user using psql and test the permissions, things will work as expected select * from users; select * from states; INSERT INTO users (user_id,user_name,state_id) VALUES (1,'test by hand',20); -- application users SQLAlchemy and connects as the test db with the postgresql login role "webuser" now when application performs an insert using syntax below (or any insert method for that matter): mystmt = users_table.insert() mystmt.execute(user_id=123,user_name='test number 1',state_id=10) When this happens in our environment using various versions of sqlalchmy including our primary version 0.7.3, we will get an exception in our app something like: ProgrammingError: (ProgrammingError) permission denied for relation states CONTEXT: SQL statement "SELECT 1 FROM ONLY "public"."states" x WHERE "id" OPERATOR(pg_catalog.=) $1 FOR SHARE OF x" 'INSERT INTO users (user_id, user_name, state_id) VALUES (% (user_id)s, %(user_name)s, %(state_id)s) RETURNING users.user_id' {'state_id': 100, , 'user_name': 'test number 1', 'user_id': 123} The permission denied is unexpected because the statement shouldn't be updating the states table only the users table. However even though webuser has select rights on the states table, postgresql requires update rights (which cannot be given for security reasons) for the FOR SHARE OF locking. I've explored with_lock on various queries and non_primary on the mapper without success. Also adding an extra column to the effected tables called fake_data and granting update rights to only that column to webuser (which would never be used in the application) while leaving all other columns read only in order to have a grant of update on the table in order to get FOR SHARE OF locking has been rejected as a viable solution. So, How do I tell SA that that the states table is read-only, OR make it shop trying to automatically lock states on insert into users, OR suppress the FOR SHARE locking on specific tables, OR do anything else that will allow the insert to run as expected with raw sql and w/o update permission on the states table, OR any combination of these things? All the best, Ryan -- You received this message because you are subscribed to the Google Groups "sqlalchemy" group. To post to this group, send email to sqlalchemy@googlegroups.com. To unsubscribe from this group, send email to sqlalchemy+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/sqlalchemy?hl=en.