Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Specify Postgres schema #2635

Answered by andrewmbenton
rickb777 asked this question in Q&A
Discussion options

What do you want to change?

I am interested to use multiple schemas in Postgres. This can for example be used to handle multiple tenants in a single database. Although it's possible to share tables across tenants, it can be better to use more than one schema instead. This isolates each tenant's data from the others. It also reduces the performance costs of each tenant's db load from impacting other tenants because tables hold fewer lines.

Is there a way to use schemas via SQL statements in SQL?

Eg select * from tenant1.user,
where I can replace tenant1 accordingly?

What database engines need to be changed?

PostgreSQL

What programming language backends need to be changed?

Go

You must be logged in to vote

Unfortunately there is no way to parameterize a schema name in a query (see this SO thread).

But you can pass a schema name as a connection parameter, which will set the search_path. So presuming you have some way of setting up a separate schema per tenant, you can scope access to that schema at the connection level.

If you are trying to avoid separate connection pools per tenant, the only thing I can think of is to run SET SCHEMA 'tenant_x_schema_name'; before every query. But I haven't actually tried that and it seems error prone. (EDIT: I don't think this is safe, see @rickb777's comment below.)

In theory sqlc could probably generate code which does that (based on a configuration), but...

Replies: 4 comments 6 replies

Comment options

Additionally, switching schemas would be a useful feature for integration tests that need to be isolated from each other. Creating temporary schemas, using them during a test run, then tearing them down afterwards is a useful technique to allow partitioning such that different tests don't interfere with each other.

You must be logged in to vote
1 reply
Comment options

Comment options

BTW the current workaround is to set up each tenant to have its own default schema in Postgres (i.e. per user role), and then use a separate connection pool with the credentials for each tenant.

This is clumsy and not ideal for the integration test use-casr.

You must be logged in to vote
1 reply
Comment options

You don't have to set up separate credentials to set up a unique schema for each tenant. But you will need separate connections per tenant if you want to scope access. See my answer below.

Comment options

Unfortunately there is no way to parameterize a schema name in a query (see this SO thread).

But you can pass a schema name as a connection parameter, which will set the search_path. So presuming you have some way of setting up a separate schema per tenant, you can scope access to that schema at the connection level.

If you are trying to avoid separate connection pools per tenant, the only thing I can think of is to run SET SCHEMA 'tenant_x_schema_name'; before every query. But I haven't actually tried that and it seems error prone. (EDIT: I don't think this is safe, see @rickb777's comment below.)

In theory sqlc could probably generate code which does that (based on a configuration), but I'm not sure it's a good idea to add the complexity if most people prefer the connection-scoped search_path.

You must be logged in to vote
0 replies
Answer selected by andrewmbenton
Comment options

When we've used this technique, we had to do a string replace on the queries, e.g.

SELECT * from public.account is mapped to SELECT * from tenant1.account

This is reliable, although it seems a bit clumsy.

I don't thing there's a reliable way to use the search_path without getting into concurrency issues because the search_path is a shared setting.

You must be logged in to vote
4 replies
Comment options

I think you are right about search_path. The only proper way to use it would be to set it on a connection pool and then maintain separate connection pools per tenant.

I don't think it's a good idea to have sqlc rewriting query strings at runtime due to the possibility of sql injection.

Comment options

Hi, could you elaborate more on the string replace step? In which phase you do that? I'm relatively new to sqlc and would like to do some multi-tenancy with shared instance, separate schema/database thing without using separate connection. Appreciate any pointers!

Comment options

Comment options

Oh never mind. I've figured it out myself. Sorry for bothering you all :)

*For anyone wondering, you can create a wrapper around DBTX interface generated by sqlc and implement the string replace there.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Category
Q&A
Labels
enhancement New feature or request
Converted from issue

This discussion was converted from issue #2633 on August 18, 2023 22:05.

AltStyle によって変換されたページ (->オリジナル) /