You can actually implement a disk quota using an updatable view with the CHECK OPTION.
Instead of giving the user access to the table, you give access to the view (at least for inserting, see the caveat at the end), and you will get a genuine MySQL error when the limit is reached.
drop table if exists logs; create table logs (t mediumtext) engine=innodb; drop function if exists exceeded_logs_quota ; create function exceeded_logs_quota() returns boolean deterministic return ( select CASE WHEN (DATA_LENGTH + INDEX_LENGTH) > (25*1024) THEN TRUE ELSE FALSE END FROM information_schema.tables WHERE table_schema=schema() and table_name='logs' ); create or replace view logsview as SELECT * FROM logs WHERE NOT exceeded_logs_quota() WITH CHECK OPTION;
Here's a test run:
mysql [localhost] {msandbox} (test) > insert into logsview values ('a'); Query OK, 1 row affected (0.00 sec) mysql [localhost] {msandbox} (test) > select exceeded_logs_quota(); +-----------------------+ | exceeded_logs_quota() | +-----------------------+ | 0 | +-----------------------+ 1 row in set (0.00 sec) mysql [localhost] {msandbox} (test) > insert into logsview values (repeat('a', (25 * 1024) - 1)); Query OK, 1 row affected (0.00 sec) mysql [localhost] {msandbox} (test) > select exceeded_logs_quota(); +-----------------------+ | exceeded_logs_quota() | +-----------------------+ | 1 | +-----------------------+ 1 row in set (0.00 sec) mysql [localhost] {msandbox} (test) > insert into logsview values ('b'); ERROR 1369 (HY000): CHECK OPTION failed 'test.logsview'
You will need to twist the limit to adapt to InnoDB habits of allocating pages rather than bytes, but if you measure the limit in MB the method should work fine.
CAVEAT: You should give your users separate privileges: SELECT on
logs
, and INSERT on logsview
. The view will only return records while exceeded_logs_quota()
returns false.mysql [localhost] {msandbox} (test) > select exceeded_logs_quota(); +-----------------------+ | exceeded_logs_quota() | +-----------------------+ | 1 | +-----------------------+ 1 row in set (0.00 sec) mysql [localhost] {msandbox} (test) > select count(*) from logsview; +----------+ | count(*) | +----------+ | 0 | +----------+ 1 row in set (0.01 sec) mysql [localhost] {msandbox} (test) > select count(*) from logs; +----------+ | count(*) | +----------+ | 2 | +----------+ 1 row in set (0.01 sec)
No comments:
Post a Comment