83

I want to create Postgres database using Python.

con = psql.connect(dbname='postgres',
      user=self.user_name, host='',
      password=self.password)

cur = con.cursor()
cur.execute("CREATE DATABASE %s  ;" % self.db_name)

I am getting the following error:

InternalError: CREATE DATABASE cannot run inside a transaction block

I am using psycopg2 to connect. I don't understand what's the problem. What am I trying to do is to connect to database (Postgres):

psql -postgres -U UserName

And then create another database:

create database test;

This is what I usually do and I want to automate this by creating Python script.

1
  • From the doc: Warning - Never, never, NEVER use Python string concatenation (+) or string parameters interpolation (%) to pass variables to a SQL query string. Not even at gunpoint. Commented Mar 23, 2022 at 20:00

3 Answers 3

116

Use ISOLATION_LEVEL_AUTOCOMMIT, a psycopg2 extensions:

No transaction is started when command are issued and no commit() or rollback() is required.

import psycopg2
from psycopg2 import sql
from psycopg2.extensions import ISOLATION_LEVEL_AUTOCOMMIT # <-- ADD THIS LINE

con = psycopg2.connect(dbname='postgres',
      user=self.user_name, host='',
      password=self.password)

con.set_isolation_level(ISOLATION_LEVEL_AUTOCOMMIT) # <-- ADD THIS LINE

cur = con.cursor()

# Use the psycopg2.sql module instead of string concatenation 
# in order to avoid sql injection attacks.
cur.execute(sql.SQL("CREATE DATABASE {}").format(
        sql.Identifier(self.db_name))
    )
Sign up to request clarification or add additional context in comments.

6 Comments

worked for me. just FYI all that you are importing is 0 the integer. so could just pass it in without bothering w extensions. and also FYI you need a separate execute call if you have to DROP DATABASE first.
@JLPeyret "all that you are importing is 0 the integer. so could just pass it in without bothering w extensions" -- true, but one can never be sure that this stays so forever. Code such as con.set_isolation_level(0) is less readable and less future-proof as named constants. Cf. the issue of C's NULL pointer. It almost always has the numerical value 0, but it would be very bad practice to say int *x = 0;. In C++11 and above, there's even a keyword nullptr for this. Although everyone "knows" that it's just 0 in all likelihood... :-)
@AndrásAszódi Null is always 0 in C. See section 6.3.2.3 open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf
@AlDante Thank you for the C standard document. In Section §7.17(3), Page 254 it says "The macros are NULL which expands to an implementation-defined null pointer constant" [emphasis mine]. I have never seen an implementation that defined a NULL different from 0, but the standard does allow it :-)
@AndrásAszódi stddef does define an implementation dependent NULL constant. But you were discussing pointers, specifically the legitimacy of assigning 0 to them. The C standard guarantees that 0 pointers are null pointers and vice versa. Whether they are equal to the NULL macro is, as you point out, implementation defined. NB I agree that it’s better to hide magic numbers behind a macro or a keyword. Just saying that a null pointer is always 0 in C, not just “in all likelihood”.
|
52

As shown in the other answer the connection must be in autocommit mode. Another way of setting it using psycopg2 is through the autocommit attribute:

import psycopg2
from psycopg2 import sql

con = psycopg2.connect(...)
con.autocommit = True

cur = con.cursor()
# sql.SQL and sql.Identifier are needed to avoid SQL injection attacks.
cur.execute(sql.SQL('CREATE DATABASE {};').format(
    sql.Identifier(self.db_name)))

2 Comments

Do we just see another SQL injection through the value of self.db_name? self.db_name = "arbitrary; DROP TABLE admin"
con.autocommit = True. fixed
3

A better and simple solution:

import psycopg # this uses psycopg version 3

def conection()
    config = {'user':'postgres',
          'password':'password_string',
              'host':'127.0.0.1',
              'port':'5432',
            'dbname':'postgres',
        'autocommit':True} #this resolve the problem "InternalError: CREATE DATABASE cannot run inside a transaction block"
    try:
        cnx = psycopg.connect(**config)
    except psycopg.Error as err:
        print(err)
        exit(1)
    else:
        return cnx

1 Comment

This doesn't actually create the database. It raises an error when the dbname doesn't exist.

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.