psycopg2.errors.ActiveSqlTransaction: CREATE DATABASE cannot run inside a transaction block

Question:

I am trying to create a Django app that creates a new database for every user when he/she signs up. I am going with this approach due to some reason. I have tried many ways using management commands and even Celery. But I am still getting the same error.

2022-12-23 07:16:07.410 UTC [49] STATEMENT:  CREATE DATABASE tenant_asdadsad
[2022-12-23 07:16:07,415: ERROR/ForkPoolWorker-4] Task user.utils.create_database[089b0bc0-0b5f-4199-8cf3-bc336acc7624] raised unexpected: ActiveSqlTransaction('CREATE DATABASE cannot run inside a transaction blockn')
Traceback (most recent call last):
 File "/usr/local/lib/python3.9/site-packages/celery/app/trace.py", line 451, in trace_task
R = retval = fun(*args, **kwargs)
File "/usr/local/lib/python3.9/site-packages/celery/app/trace.py", line 734, in __protected_call__
return self.run(*args, **kwargs)
File "/app/user/utils.py", line 45, in create_database
cursor.execute(f'CREATE DATABASE tenant_{tenant_id}')
psycopg2.errors.ActiveSqlTransaction: CREATE DATABASE cannot run inside a transaction block

This is my task

@shared_task
def create_database(tenant_id):
  conn = psycopg2.connect(database="mydb", user="dbuser", password="mypass", host="db")
  cursor = conn.cursor()
  transaction.set_autocommit(True)
  cursor.execute(f'CREATE DATABASE tenant_{tenant_id}')
  cursor.execute(f'GRANT ALL PRIVILEGES ON DATABASE tenant_{tenant_id} TO dbuser')
  cursor.close()
  conn.close()

I have tried several ways but I always get the same error

This is my API call

def create(self, request, *args, **kwargs):
    serializer_class = mySerializer(data=request.data)
    if serializer_class.is_valid():
        validated_data = serializer_class.validated_data
        or = validated_data["org"]
        or = Org.objects.create(**org)
        create_database.delay(str(or.id))
        return Response(create_user(validated_data))
Asked By: Abdullah Mujahid

||

Answers:

Use the autocommit property of the connection:

from psycopg2 import sql

def create_database(tenant_id):
  conn = psycopg2.connect(database="mydb", user="dbuser", password="mypass", host="db")
  cursor = conn.cursor()
  conn.autocommit = True #!
#  transaction.set_autocommit(True) #?
  dbname = sql.Identifier(f'tenant_{tenant_id}')
  create_cmd = sql.SQL('CREATE DATABASE {}').format(dbname)
  grant_cmd = sql.SQL('GRANT ALL PRIVILEGES ON DATABASE {} TO dbuser').format(dbname)
  cursor.execute(create_cmd)
  cursor.execute(grant_cmd)
  cursor.close()
  conn.close()

Read in the docs about connection.autocommit.

Note also the use of the SQL string composition to avoid SQL injection.

Answered By: klin
Categories: questions Tags: , , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.