Меню

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

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$;

0 0 голоса
Рейтинг статьи
Подписаться
Уведомить о
guest

0 комментариев
Старые
Новые Популярные
Межтекстовые Отзывы
Посмотреть все комментарии

А вот еще интересные материалы:

  • Яшка сломя голову остановился исправьте ошибки
  • Ясность цели позволяет целеустремленно добиваться намеченного исправьте ошибки
  • Ясность цели позволяет целеустремленно добиваться намеченного где ошибка
  • Error while unpacking program code lp5 please report to author ошибка
  • Error while executing the query ошибка