Error ошибка drop database не может выполняться внутри блока транзакции

I am working on AWS server + PostgreSQL. When I execute a query for creating the database I get an error:

CREATE DATABASE cannot run inside a transaction block

I am working on Linux Ubuntu 12.04 LTS.

How can I resolve this issue?

Eric Leschinski's user avatar

asked Oct 21, 2014 at 9:01

Nikunj K.'s user avatar

4

I have used turn on autocommit in PostgreSQL and it’s working for me.

Here is the query to turn on the autocommit

SET AUTOCOMMIT = ON

Note that this only works for PostgreSQL 9.4 and below

Lord Elrond's user avatar

Lord Elrond

13.1k6 gold badges38 silver badges77 bronze badges

answered Oct 21, 2014 at 9:45

Nikunj K.'s user avatar

Nikunj K.Nikunj K.

8,6734 gold badges43 silver badges53 bronze badges

8

Note, for postgres 9.5+ you have to use:

psql -c 'set AUTOCOMMIT on'

But I’m going to guess, that what you really wanted to do is destroy the database and recreate it in a single command. Here you go:

printf 'set AUTOCOMMIT onndrop database <your_db_here>; create database <your_db_here>; ' |  psql postgres

answered Nov 20, 2020 at 22:27

Javier Buzzi's user avatar

Javier BuzziJavier Buzzi

6,21436 silver badges50 bronze badges

In Postgres SQL 14.1, pgAdmin query tool, I see this same error when running the create database query with other queries. Running the create database query by itself completes successfully.

answered Dec 10, 2021 at 18:24

Asencion's user avatar

AsencionAsencion

1991 silver badge11 bronze badges

With psql you can also run drop and and create your database in one command by using multiple --command arguments:

psql postgres -c "drop database if exists <your_db_here>;" -c "create database <your_db_here>;"

answered Feb 21 at 7:52

mpoqq's user avatar

mpoqqmpoqq

765 bronze badges

This can also happen if you have commented lines within a create table block

problem code:

CREATE TABLE users (
    user_id SERIAL PRIMARY KEY,
    first_name VARCHAR(30),
    last_name VARCHAR(30) NOT NULL,
    date_of_birth DATE
-- managers INT FOREIGN KEY,
-- employees INT FOREIGN KEY,
-- companies INT FOREIGN KEY
);


Solution:

CREATE TABLE users (
    user_id SERIAL PRIMARY KEY,
    first_name VARCHAR(30),
    last_name VARCHAR(30) NOT NULL,
    date_of_birth DATE
);

-- managers INT FOREIGN KEY,
-- employees INT FOREIGN KEY,
-- companies INT FOREIGN KEY

answered May 14, 2021 at 18:58

ScottyBlades's user avatar

ScottyBladesScottyBlades

11.8k5 gold badges74 silver badges81 bronze badges

0

I did through Query Tools and got your error. To resolve this problem, I opened PSQL Tool and then created my database in.

  1. sudo su - postgres

  2. psql -d postgres -U postgres

  3. create database dbName;

answered Dec 14, 2022 at 8:34

ParisaN's user avatar

ParisaNParisaN

1,7822 gold badges22 silver badges53 bronze badges

Not really sure if this question belongs here, but I hope someone could help me out.

I’ve made integration tests going all the way down to the database (using mssql localDB). I want each test to run independently with it’s own data — I want to reseed the database with my fake data before each test is running. I tried to implement it with transactions without success. Here is how I tried to pull it off:

public class TestDbInitializer : DropCreateAlways<MyContext>()
{
    public static List<Item> Items;

    public override Seed(DbContext context)
    {
        Items = new List<Item>();

        // Adding items
        // .. 

        Items.ForEach(x => context.Add(x));

        context.SaveChanges();
    }
}


public class BaseTransactionsTests
{
    private TransactionScope _scope

    [TestInitialize]
    public void Initialize()
    {
        _scope = new TransactionScope();
    }

    [TestCleanup]
    public void Cleanup()
    {
        _scope.Dispose();
    }
}

[TestClass]
public class IntegrationTests : BaseTransactionsTests

private IDependenciesContainer _container;

public static void AssemblyInit(TestContext context)
{
    Database.SetInitializer(new TestDbInitializer());

    _container = new DependenciesContainer();

    // Registers all my application's dependencies
    _container.RegisterAll();
}

[TestInitialize]
public void Initialize()
{
    using (var context = new MyContext("TestsDatabase"))
    {
        context.Initialize(true);
    }
}

[TestMethod]
public void TestAddItem()
{
    var controller = _container.Resolve<MyController>();

    var result = controller.AddItem(new Item({Name = "Test"}))

    var goodResult = result as OkNegotiatedResult<string>();

    if (result == null)
        Assert.Fail("Bad result")

    using (var context = new MyContext("TestsDatabase"))
    {
        Assert.AreEqual(context.Items.Count, TestDbInitializer.Items.Count + 1)
    }
}

I use my dependency injector in my tests, registering all dependencies once (AssemblyInitialize).

I created a DB instance for testings, and a specific DropCreateAlways initializer with a fake data Seed method, which I set as the initializer in the AssemblyInitialize as well.

I want to reseed the database with my fake data before each test run. For that case I implemented the base class which holds a transaction scope.

When I run my tests, the following exception is thrown when Seeding the database in the TestInitialize:

DROP DATABASE statement cannot be used inside a user transaction

How should I deal with it? Moreover, what do you think of my implementation of those integration tests? What could be improved?

Not really sure if this question belongs here, but I hope someone could help me out.

I’ve made integration tests going all the way down to the database (using mssql localDB). I want each test to run independently with it’s own data — I want to reseed the database with my fake data before each test is running. I tried to implement it with transactions without success. Here is how I tried to pull it off:

public class TestDbInitializer : DropCreateAlways<MyContext>()
{
    public static List<Item> Items;

    public override Seed(DbContext context)
    {
        Items = new List<Item>();

        // Adding items
        // .. 

        Items.ForEach(x => context.Add(x));

        context.SaveChanges();
    }
}


public class BaseTransactionsTests
{
    private TransactionScope _scope

    [TestInitialize]
    public void Initialize()
    {
        _scope = new TransactionScope();
    }

    [TestCleanup]
    public void Cleanup()
    {
        _scope.Dispose();
    }
}

[TestClass]
public class IntegrationTests : BaseTransactionsTests

private IDependenciesContainer _container;

public static void AssemblyInit(TestContext context)
{
    Database.SetInitializer(new TestDbInitializer());

    _container = new DependenciesContainer();

    // Registers all my application's dependencies
    _container.RegisterAll();
}

[TestInitialize]
public void Initialize()
{
    using (var context = new MyContext("TestsDatabase"))
    {
        context.Initialize(true);
    }
}

[TestMethod]
public void TestAddItem()
{
    var controller = _container.Resolve<MyController>();

    var result = controller.AddItem(new Item({Name = "Test"}))

    var goodResult = result as OkNegotiatedResult<string>();

    if (result == null)
        Assert.Fail("Bad result")

    using (var context = new MyContext("TestsDatabase"))
    {
        Assert.AreEqual(context.Items.Count, TestDbInitializer.Items.Count + 1)
    }
}

I use my dependency injector in my tests, registering all dependencies once (AssemblyInitialize).

I created a DB instance for testings, and a specific DropCreateAlways initializer with a fake data Seed method, which I set as the initializer in the AssemblyInitialize as well.

I want to reseed the database with my fake data before each test run. For that case I implemented the base class which holds a transaction scope.

When I run my tests, the following exception is thrown when Seeding the database in the TestInitialize:

DROP DATABASE statement cannot be used inside a user transaction

How should I deal with it? Moreover, what do you think of my implementation of those integration tests? What could be improved?

I am working on AWS server + PostgreSQL. When I execute a query for creating the database I get an error:

CREATE DATABASE cannot run inside a transaction block

I am working on Linux Ubuntu 12.04 LTS.

How can I resolve this issue?

Eric Leschinski's user avatar

asked Oct 21, 2014 at 9:01

Nikunj K.'s user avatar

4

I have used turn on autocommit in PostgreSQL and it’s working for me.

Here is the query to turn on the autocommit

SET AUTOCOMMIT = ON

Note that this only works for PostgreSQL 9.4 and below

Lord Elrond's user avatar

Lord Elrond

12.3k6 gold badges35 silver badges71 bronze badges

answered Oct 21, 2014 at 9:45

Nikunj K.'s user avatar

Nikunj K.Nikunj K.

8,4774 gold badges43 silver badges52 bronze badges

7

Note, for postgres 9.5+ you have to use:

psql -c 'set AUTOCOMMIT on'

But I’m going to guess, that what you really wanted to do is destroy the database and recreate it in a single command. Here you go:

printf 'set AUTOCOMMIT onndrop database <your_db_here>; create database <your_db_here>; ' |  psql postgres

answered Nov 20, 2020 at 22:27

Javier Buzzi's user avatar

Javier BuzziJavier Buzzi

5,93535 silver badges49 bronze badges

In Postgres SQL 14.1, pgAdmin query tool, I see this same error when running the create database query with other queries. Running the create database query by itself completes successfully.

answered Dec 10, 2021 at 18:24

Asencion's user avatar

AsencionAsencion

1691 silver badge10 bronze badges

This can also happen if you have commented lines within a create table block

problem code:

CREATE TABLE users (
    user_id SERIAL PRIMARY KEY,
    first_name VARCHAR(30),
    last_name VARCHAR(30) NOT NULL,
    date_of_birth DATE
-- managers INT FOREIGN KEY,
-- employees INT FOREIGN KEY,
-- companies INT FOREIGN KEY
);


Solution:

CREATE TABLE users (
    user_id SERIAL PRIMARY KEY,
    first_name VARCHAR(30),
    last_name VARCHAR(30) NOT NULL,
    date_of_birth DATE
);

-- managers INT FOREIGN KEY,
-- employees INT FOREIGN KEY,
-- companies INT FOREIGN KEY

answered May 14, 2021 at 18:58

ScottyBlades's user avatar

ScottyBladesScottyBlades

11.1k5 gold badges70 silver badges76 bronze badges

0

I did through Query Tools and got your error. To resolve this problem, I opened PSQL Tool and then created my database in.

  1. sudo su - postgres

  2. psql -d postgres -U postgres

  3. create database dbName;

answered Dec 14, 2022 at 8:34

ParisaN's user avatar

ParisaNParisaN

1,5592 gold badges20 silver badges52 bronze badges

Сообщение об ошибке так же ясно, как руководство на этом:

DROP DATABASE не может выполняться внутри блока транзакции.

Функция plgpsql автоматически окружается блоком транзакции. Короче говоря, вы не можете сделать это напрямую. Есть ли особая причина, по которой вы не можете просто вызвать команду DDL?

DROP database $mydb;

Ты может обойти эти ограничения с помощью дополнительного модуля дблинк as @ Игорь предложенный. Вам нужно установить его один раз для каждой базы данных — ту, в которой вы вызываете функции dblink, а не (другую), в которой вы выполняете команды.
Позволяет написать функцию, используя dblink_exec() как это:

CREATE OR REPLACE FUNCTION f_drop_db(text)
  RETURNS text LANGUAGE sql AS
$func$
SELECT dblink_exec('port=5432 dbname=postgres'
                  ,'DROP DATABASE ' || quote_ident($1))
$func$;

quote_ident() предотвращает возможную SQL-инъекцию.

Звоните:

SELECT f_drop_db('mydb');

В случае успеха вы видите:

УДАЛИТЬ БАЗУ ДАННЫХ

Строка подключения может даже указывать на ту же базу данных, в которой работает ваш сеанс. Команда выполняется за пределами блока транзакции, что имеет два последствия:

  • Его нельзя откатить назад.
  • Он позволяет вам звонить DROP DATABASE «через прокси» из функции.

Вы могли бы создать FOREIGN DATA WRAPPER и FOREIGN SERVER чтобы сохранить соединение и упростить вызов:

CREATE FOREIGN DATA WRAPPER postgresql VALIDATOR postgresql_fdw_validator;

CREATE SERVER your_fdw_name_here FOREIGN DATA WRAPPER postgresql
OPTIONS (hostaddr '12.34.56.78', port '5432', dbname 'postgres');

Использование базы данных обслуживания по умолчанию postgres, что было бы очевидным выбором. Но возможна любая БД.

Упрощенная функция, использующая это:

CREATE OR REPLACE FUNCTION f_drop_db(text)
  RETURNS text LANGUAGE sql AS
$func$
SELECT dblink_exec('your_fdw_name_here', 'DROP DATABASE ' || quote_ident($1))
$func$;

выходит такая ошибка:

ERROR: ОШИБКА:  CREATE DATABASE не может выполняться внутри блока транзакции


SQL-состояние: 25001

А вот и сам код:

CREATE DATABASE "KATLA"
    WITH 
    OWNER = postgres
    ENCODING = 'UTF8'
    LC_COLLATE = 'Russian_Russia.1251'
    LC_CTYPE = 'Russian_Russia.1251'
    TABLESPACE = pg_default
    CONNECTION LIMIT = -1;
-- PostgreSQL database dump
--

-- Dumped from database version 14.3
-- Dumped by pg_dump version 14.2

-- Started on 2022-06-06 14:35:09

SET statement_timeout = 0;
SET lock_timeout = 0;
SET idle_in_transaction_session_timeout = 0;
SET client_encoding = 'UTF8';
SET standard_conforming_strings = on;
SELECT pg_catalog.set_config('search_path', '', false);
SET check_function_bodies = false;
SET xmloption = content;
SET client_min_messages = warning;
SET row_security = off;

--
-- TOC entry 2 (class 3079 OID 16384)
-- Name: adminpack; Type: EXTENSION; Schema: -; Owner: -
--

CREATE EXTENSION IF NOT EXISTS adminpack WITH SCHEMA pg_catalog;


--
-- TOC entry 3239 (class 0 OID 0)
-- Dependencies: 2
-- Name: EXTENSION adminpack; Type: COMMENT; Schema: -; Owner: 
--

COMMENT ON EXTENSION adminpack IS 'administrative functions for PostgreSQL';


SET default_tablespace = '';

SET default_table_access_method = heap;

--
-- TOC entry 213 (class 1259 OID 16427)
-- Name: prodagiDB; Type: TABLE; Schema: public; Owner: postgres
--

CREATE TABLE public."prodagiDB" (
    name character varying(255) NOT NULL,
    id uuid NOT NULL,
    prodaji integer NOT NULL
);


ALTER TABLE public."prodagiDB" OWNER TO postgres;

--
-- TOC entry 210 (class 1259 OID 16395)
-- Name: t1; Type: TABLE; Schema: public; Owner: postgres
--

CREATE TABLE public.t1 (
    "Петров" character varying(255) NOT NULL,
    id text NOT NULL
);


ALTER TABLE public.t1 OWNER TO postgres;

--
-- TOC entry 3240 (class 0 OID 0)
-- Dependencies: 210
-- Name: TABLE t1; Type: COMMENT; Schema: public; Owner: postgres
--

COMMENT ON TABLE public.t1 IS 'задачи пользователя';


--
-- TOC entry 211 (class 1259 OID 16398)
-- Name: test2; Type: TABLE; Schema: public; Owner: postgres
--

CREATE TABLE public.test2 (
);


ALTER TABLE public.test2 OWNER TO postgres;

--
-- TOC entry 212 (class 1259 OID 16401)
-- Name: test3; Type: TABLE; Schema: public; Owner: postgres
--

CREATE TABLE public.test3 (
);


ALTER TABLE public.test3 OWNER TO postgres;

--
-- TOC entry 3233 (class 0 OID 16427)
-- Dependencies: 213
-- Data for Name: prodagiDB; Type: TABLE DATA; Schema: public; Owner: postgres
--

INSERT INTO public."prodagiDB" (name, id, prodaji) VALUES ('Петров', '959416a1-92eb-4124-a951-a547c2df0d20', 25);
INSERT INTO public."prodagiDB" (name, id, prodaji) VALUES ('Иванов', '6c67fe46-94a4-4891-a7b4-c6041fee7bc6', 30);


--
-- TOC entry 3230 (class 0 OID 16395)
-- Dependencies: 210
-- Data for Name: t1; Type: TABLE DATA; Schema: public; Owner: postgres
--



--
-- TOC entry 3231 (class 0 OID 16398)
-- Dependencies: 211
-- Data for Name: test2; Type: TABLE DATA; Schema: public; Owner: postgres
--



--
-- TOC entry 3232 (class 0 OID 16401)
-- Dependencies: 212
-- Data for Name: test3; Type: TABLE DATA; Schema: public; Owner: postgres
--



--
-- TOC entry 3090 (class 2606 OID 16431)
-- Name: prodagiDB prodagiDB_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres
--

ALTER TABLE ONLY public."prodagiDB"
    ADD CONSTRAINT "prodagiDB_pkey" PRIMARY KEY (id);


--
-- TOC entry 3088 (class 2606 OID 16418)
-- Name: t1 t1_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres
--

ALTER TABLE ONLY public.t1
    ADD CONSTRAINT t1_pkey PRIMARY KEY (id);


-- Completed on 2022-06-06 14:35:09

--
-- PostgreSQL database dump complete
--

Вопрос:

У меня есть функция, которая выглядит так:

BEGIN
DROP DATABASE IF EXISTS db_1;
END;

Я получаю следующую ошибку:

ОШИБКА: DROP DATABASE не может быть выполнена из строки функции или нескольких команд.

Невозможно ли удалить базу данных из хранимой процедуры в PostgreSQL? Я использую plpgsql.

Ответ №1

вы не можете сделать это из процедуры, потому что drop database не может выполняться внутри транзакции, а хранимая процедура рассматривается как сама транзакция. (См. ссылка)

Как насчет dropdb?

Ответ №2

Сообщение об ошибке просто ясно: руководство:

DROP DATABASE не может выполняться внутри блока транзакций.

Функция plgpsql автоматически окружена блоком транзакций. Долгое и короткое: вы не можете этого сделать – напрямую. Есть ли конкретная причина, по которой вы не можете просто вызвать команду DDL?

DROP database $mydb;

Вы можете обойти эти ограничения с помощью дополнительного модуля dblink как @Igor. Вам нужно установить его один раз на базу данных – ту, где вы вызываете функции dblink, а не (другую), которую вы выполняете в команде.
Позволяет вам написать функцию dblink_exec() следующим образом:

CREATE OR REPLACE FUNCTION f_drop_db(text)
RETURNS text LANGUAGE sql AS
$func$
SELECT dblink_exec('port=5432 dbname=postgres'
,'DROP DATABASE ' || quote_ident($1))
$func$;

quote_ident() предотвращает возможную инъекцию SQL.

Вызов:

SELECT f_drop_db('mydb');

Успех вы видите:

DROP DATABASE

Строка подключения может даже указывать на тот же бит, в котором выполняется ваш сеанс. Команда запускается за пределами транзакционного блока, что имеет два последствия:

  • Его нельзя отменить.
  • Позволяет вам вызывать DROP DATABASE “через прокси” изнутри функции.

Вы можете создать FOREIGN DATA WRAPPER и FOREIGN SERVER, чтобы сохранить соединение и упростить вызов:

CREATE FOREIGN DATA WRAPPER postgresql VALIDATOR postgresql_fdw_validator;

CREATE SERVER your_fdw_name_here FOREIGN DATA WRAPPER postgresql
OPTIONS (hostaddr '12.34.56.78', port '5432', dbname 'postgres');

Использование обслуживания по умолчанию db postgres, что было бы очевидным выбором. Но любой db возможен.

Упрощенная функция, использующая это:

CREATE OR REPLACE FUNCTION f_drop_db(text)
RETURNS text LANGUAGE sql AS
$func$
SELECT dblink_exec('your_fdw_name_here', 'DROP DATABASE ' || quote_ident($1))
$func$;

Ekrem Önsoy
December 16, 2018
MSSQL

ERROR MESAGGE:

“DROP DATABASE statement cannot be used inside a user transaction”

EXPLANATION:

You may receive this error message when you try to delete a database with the “DROP DATABASE” command.

SOLUTION:

If you receive this error message, Transaction in the session where you run this command has remained open. Use the ROLLBACK or COMMIT commands to end this Transaction, or another session, and run the ’DROP DATABASE komut command again.

Loading

About Ekrem Önsoy

The original article was written in Turkish by Ekrem Önsoy and translated to English by dbtut with the consent of the author. The copyright of the article belongs to the author. The author shall not be liable in any way for any defect caused by translation.

  • Error какие бывают ошибки
  • Error как удалить ошибку
  • Error while unpacking program code lp5 please report to author ошибка
  • Error while executing the query ошибка
  • Error while evaluating uicontrol callback ошибка как решить