3

We are trying to limit the number of registrations on our SIP server in the simplest way possible. More specifically, we have decided to limit the number of entries in the users table. The server is running PostgreSQL as the DBMS.

Is it possible to limit the number of entries in a specific table? For example, we want to limit the number of rows to 100 and we do not want any more entries on that table unless some of the old ones are deleted.

Please advise.

3 Answers 3

4

It's possible, but that's a pretty bad way of solving this problem. You'll have to create a trigger that acquires an EXCLUSIVE lock on the table then checks the count() on the table before allowing a commit or, if the insert would add too many rows, doing a RAISE EXCEPTION to abort the transaction.

Two triggers, actually; a BEFORE INSERT OR DELETE trigger that does the LOCK TABLE ... IN EXCLUSIVE MODE and an AFTER INSERT trigger that checks the COUNT of the table and decides whether to raise an exception. A simple BEFORE trigger is insufficient, since it can't tell if an INSERT might add more than one row, so a multi-valued insert or INSERT ... SELECT might cause the limit to be exceeded.

Other sessions that want to update the table will have to wait until the transaction doing the INSERT finishes. If the app isn't designed for this it could easily cause deadlocks.

The app probably doesn't expect to get an error when it INSERTs into the sessions table so it might not deal with that gracefully. It's rather unlikely to give the user a neat "too many registrations" error.

I haven't written a sample trigger for this because I think it's an absolutely terrible idea to do this. If you want to set a limit on how many users can be registered in your SIP server, configure your SIP server appropriately. If there's no such config option, modify it to add one or use a different SIP server that does have one.

Sign up to request clarification or add additional context in comments.

2 Comments

I wonder if a slightly different method might work in lieu of triggers, such as 100 entries in the table and each SIP "user" needs to claim an entry and subsequent attempts block or fail if they cannot get an entry. As you say Craig, I think a more appropriate solution is fixing the application.
@bma That'd work, but would be prone to race conditions that would be hard to solve without landing back at the same sort of single-threaded approach or more application changes. How do you pick which one to claim in the face of concurrent inserts and deletes? If Pg supported LIMIT 1 SKIP LOCKED or something you could do it, but at present there's nothing like that.
1

It is a little bit late, but we had the same problem so I would like to share my solution. I assume that user table have some parent key or some relation. You can do it in transaction by locking the parent record and checking a count of total users that meet your condition. If it is less than limit then you can insert new user. If you try to do that in another transaction you will be locked until the first one finished, or you can use SKIP LOCKED to get an empty result and finish the transaction.

Code:

BEGIN;
SELECT * FROM user_parent WHERE /* condition */ FOR UPDATE;
SELECT count(1) FROM "user" WHERE /* condition */;
// check count in your code
// if count <= limit; then continue; else ROLLBACK
// INSERT your users
COMMIT;

Comments

0

As usual, google brought me over here :

CONSTRAINT nomore_than_x_rows
CHECK( table_id < 101 ); 

given that the id is of type serial

1 Comment

This tecnique would work only if users are never deleted, because, if you delete a user, the new ids will be higher than 100.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.