How alter database name - database

I'm trying to alter database name on phppgadmin but i'm always getting this error:
ERROR: database "X" is being accessed by other users
DETAIL: There are 19 other sessions using the database.
Nobody is accessed except me so i don't understand this error.
How can i change the database name, or force it even when there are 19 other sessions using the database ?
Thank you

There may some auto connectivity. you may first terminate all the connection to your DB using below command:
SELECT
pg_terminate_backend(pid)
FROM
pg_stat_activity
WHERE
-- don't kill my own connection!
pid <> pg_backend_pid()
-- don't kill the connections to other databases
AND datname = 'database_name'
;
Before executing this query, you have to REVOKE the CONNECT privileges to avoid new connections:
REVOKE CONNECT ON DATABASE dbname FROM PUBLIC, username;
If you're using Postgres 8.4-9.1 use procpid instead of pid
SELECT
pg_terminate_backend(procpid)
FROM
pg_stat_activity
WHERE
-- don't kill my own connection!
procpid <> pg_backend_pid()
-- don't kill the connections to other databases
AND datname = 'database_name'
;
After the above , try renaming your DB.
reference: Kill a postgresql session/connection
UPDATE
For future reference, you should be able to:
-- disconnect from the database to be renamed
\c postgres
-- force disconnect all other clients from the database to be renamed
SELECT pg_terminate_backend( pid )
FROM pg_stat_activity
WHERE pid <> pg_backend_pid( )
AND datname = 'name of database';
-- rename the database (it should now have zero clients)
ALTER DATABASE "name of database" RENAME TO "new name of database";
Note that table pg_stat_activity column pid was named as procpid in versions prior to 9.2. So if your PostgreSQL version is lower than 9.2, use procpid instead of pid.
reference: PostgreSQL - Rename database

Related

MS SQL/Powershell: how to kill background process on secondary node in Availability Group

I have an environment with MS-SQL Server 2014 and always-on high availability group configured (on 2-nodes).
I'm writing a Powershell Script which removes the database from the availability group (on the primary server) and then SHOULD drop the database on the secondary Server.
That works most of the time, but not always...
I use this the following command to drop the database on the secondary Server (the db is by this time already removed from the availability group on the primary server and is in state "recovering" on the secondary server):
$SecondaryServerConnection.Databases[$x.Name.ToString()].Drop()
When it fails, i get the error message:
System.Management.Automation.MethodInvocationException: Exception calling "Drop" with "0" argument(s): "Drop failed for Database
'Customer_2'. " ---> Microsoft.SqlServer.Management.Smo.FailedOperationException: Drop failed for Database 'Customer_2'.
---> Microsoft.SqlServer.Management.Common.ExecutionFailureException: An exception occurred while executing a Transact-SQL statement or
batch. ---> System.Data.SqlClient.SqlException: Cannot drop database "Customer_2" because it is currently in use.
When i check the DB-Server (sp_who2) while the script is running, i see that there is a process for the DB "Customer_2" with Status="background", Command="DB STARTUP" and LastWaitType="REDO_THREAD_PENDING WORK".
As soon as the script fails, the process for "Customer_2" disapears.
I tried to modify my script to kill all processes, but when I do that, I get the error message: Only user processes can be killed.
If it happens, it happens always on the second Database. In the availability group are several databases (3 - 5).
So, now I have several questions:
How do I get rid of that background process within my Powershell script? Is it possible to do that??
Why does it work with the first database and not on the second? Does my script have a process on that DB and therefore the process only disappears after the script fails??
Or is it a timing issue, after i've dropped the database on the primary server?? I have a 6 seconds start-sleep after the drop..
What are these processes anyway? They are there for all the databases on the secondary server.
I haven't found a reason why it works on some databases and does not on some others.. It might be an issue with the size of the database.. Some are just a few hundred MB, while others are up to 40Gb...
I cant set the database offline or set it to single user mode, because the database is not online on the secondary server. The database is in state "Restoring".
UPDATE:
Something I forgot to mention is that the SPID of the process is normally above 50 . From what I was reading, SPID below 50 are always system processes. Is that correct?
You can try this script, which will kill any and all active processes in a specified database:
DECLARE #sql varchar(50);
DECLARE #dbname sysname;
DECLARE #killStmts TABLE (stmt varchar(30));
SET #dbname = 'yourDatabase'; -- Set this to your database name
INSERT INTO #killStmts
SELECT 'KILL ' + CONVERT(varchar(10), [spid])
FROM master..sysprocesses pr
INNER JOIN master..sysdatabases db ON pr.[dbid] = db.[dbid]
WHERE db.name = #dbname
DECLARE #killCtr int;
SELECT #killCtr = COUNT(1) FROM #killStmts;
WHILE (#killCtr > 0)
BEGIN
SELECT TOP 1 #sql = stmt FROM #killStmts ORDER BY stmt;
EXEC (#sql);
DELETE #killStmts WHERE stmt = #sql;
SELECT #killCtr = #killCtr - 1;
END
You can adapt this into a stored procedure (install it into the master database so you can call it for any other user database you like) which can be invoked by PowerShell, or you can try to adapt this script to PowerShell itself.
I found a solution to this issue (but not what the source of that problem was).
I ended up writing a Powershell function that tries with 3 different methods to drop the database
Function Remove-SqlDatabase
{
[CmdletBinding()]
Param(
[string]$Server,
[string]$Database
)
try
{
$smo = New-SMOconnection -server $Server
$smo.KillDatabase($Database)
$smo.Refresh()
#Write-Host "Successfully dropped $Database on $($smo.name)"
}
catch
{
try
{
$smo.Databases[$Database].Drop()
#Write-Host "Successfully dropped $Database on $($smo.name)"
}
catch
{
try
{
$null = $smo.ConnectionContext.ExecuteNonQuery("DROP DATABASE $Database")
#Write-Host "Successfully dropped $Database on $($smo.name)"
}
catch
{
Write-Error "Could not drop database $Database!"
Write-Error $_
throw $_
}
}
}
}

Why SQL Server doesn't allow to remove a Distributor exactly after Configuration?

I Configured a distribution in SQL Server 2008 using both Wizard and T-SQL but after it when I want to remove it Using Wizard (right clicking on Replication and choosing 'Disable Publishing and Distribution...') or executing following command with and without its parameters:
exec sp_dropdistributor #no_checks = 1 -- no new results with #ignore_distributor = 1
this Error would be presented:
Msq 21122, Level 16, State 1, Procedure sp_dropdistributiondb Line 124
Cannot drop the distribution database 'lobloblob' because it is
currently in use.
I didn't publish any thing, didn't configure any subscription but gave this error
what should I do ?
Try this:
SELECT spid FROM sys.sysprocesses WHERE dbid = db_id('distribution')
Kill the spid and try again. Now it should work.
I used the following scripts:
SELECT spid FROM sys.sysprocesses WHERE dbid = db_id('distribution')
and found that the session_id of current session (which contains the distribution configuration script) doesn't allow to disable distribution so i suggest this script to kill running spid to drop distribution:
use [master]
declare #spid varchar(10)
select #spid=spid from sys.sysprocesses where dbid = DB_ID('distribution')
while ##ROWCOUNTS <> 0
exec ('KILL ' + #spid)
exec sp_dropdistributor #no_checks = 1
My guess would be that the distribution cleanup job is causing the problem. But, to check, prepare to execute the sp_dropdistributor in one window in SSMS and note the session_id of the window. In a second, prepare to run select session_id from sys.dm_os_waiting_tasks where blocked_session_id = <spid from window 1>. Back in window 1, run the proc and then switch back to window 2 and run the select. it'll tell you the session_ids of the sessions blocking the drop of the database.

SQL Server 2008 R2 Cross Database Ownership Chaining Not working?

I have restored two SQL Server 2005 dbs (DB1 & DB2) to a new box running SQL Server 2008 R2.
All objects are owned by dbo
I have a stored procedure DB1.dbo.mp_SPTest. I have given execute permissions to SQLUser1.
CREATE PROCEDURE mp_SPTest
AS
SELECT DB2.dbo.mf_UserHasAccess("BasicUser", "bob")
mp_SPTest calls a scalar function in DB2 DB2.dbo.mf_UserHasAccess(), this function checks if the username passed is a member of a SQL Role.....
CREATE FUNCTION [dbo].[mf_UserHasAccess] (#RoleName varchar(50), #UserName varchar(128))
RETURNS bit
AS
BEGIN
DECLARE #Result bit
SELECT #Result = 1
WHERE #RoleName IN (
SELECT CASE
WHEN (usg.uid is null) THEN 'public'
ELSE usg.name
END AS RoleName
FROM dbo.sysusers usu
LEFT OUTER JOIN (dbo.sysmembers mem
INNER JOIN dbo.sysusers usg
ON mem.groupuid = usg.uid)
ON usu.uid = mem.memberuid
LEFT OUTER JOIN master.dbo.syslogins lo
ON usu.sid = lo.sid
WHERE
(usu.islogin = 1 AND usu.isaliased = 0 AND usu.hasdbaccess = 1)
AND (usg.issqlrole = 1 OR usg.uid is NULL)
AND usu.name = #UserName)
IF #Result <> 1
BEGIN
SET #Result = 0
END
RETURN #Result
END
When I run this procedure as "SQLUser1" it tells me that bob is not a member of BasicUser but when I run it as "sa" it tells me that he IS a member.
As I understand it... because both procedure and function are owned by dbo then that is the context that the function in test2 db would run, therefore it should have access to the same user and login tables.
This worked fine on SQL Server 2005, cant figure it out.
Hope this makes sense, thanks in advance.
Most likely the old SQL Server 2005 had the cross db ownership chaining option turned on, while the new SQL Server 2008 R2 instance has the option left at its default value (off).
But your assumption that 'dbo' in DB1 equate to 'dbo' in DB2 is wrong. 'dbo' in DB1 is the login who corresponds to the owner_sid of DB1 in sys.databases. 'dbo' in DB2 is, likewise, the login that corrsponds to the onwer_sid in sys.databases for DB2. If the two logins are different (if the owner_sid of the two databases is different) then very likely 'dbo' of DB1 will map to some other user and the ownership chain is broken, even if enabled to cross databases. Running ALTER AUTHORIZATION ON DATABASE::[DB..] TO [sa] would fix this problem (ie. it would force the owner_sid to match).
And finally, what you're doing is fundamentally flawed, as it relies on activating ownership chaining across databases, which is a huge security hole, see Potential Threats. A much better avenue is to use code signing.
I solved this identical problem by making the schema the view or procedure is running under the owner of the schemas in the databases it needs to access.
USE [TargetDB]
ALTER AUTHORIZATION ON SCHEMA::[TargetSchema] TO [SourceSchema]
For example
USE [DB1]
ALTER AUTHORIZATION ON SCHEMA::[mem] TO [dbo]
GO
Would allow a view run as DB2.DBO.view assuming chaining is turned on, to access a table in DB1.mem.table. Essentially cross db chaining causes it to access the target DB AS the schema the view is under, not the user who owns the database.

Enabling broker after Restoring Sql Server DataBase

I have DataBase with enabled Service Broker. Then I want to restore my database in program from backup of other database, but after restoring(I restore on existing database name), my method, whitch enables Service Broker, puts this error:
Msg 9772, Level 16, State 1, Line 1
The Service Broker in database "ServeDB2" cannot be enabled because there is already an enabled Service Broker with the same ID.
Msg 5069, Level 16, State 1, Line 1
ALTER DATABASE statement failed.
This is my method:
public void TurnOnBroker()
{
if (!this.database.BrokerEnabled)
{
this.server.KillAllProcesses(this.database.Name);
this.database.BrokerEnabled = true;
this.database.Alter();
RefreshConnection();
}
}
What should i fix here?Any suggestions?
keep a note of these options
ALTER DATABASE mydb SET ENABLE_BROKER
ALTER DATABASE mydb SET DISABLE_BROKER
ALTER DATABASE mydb SET NEW_BROKER
if youre getting something like this is already an enabled Service Broker with the same ID, go for the NEW_BROKER
ALTER DATABASE [Database_name] SET NEW_BROKER WITH ROLLBACK IMMEDIATE;
This will create the new service broker
Every database has a unique ID used by Service Broker. This ID must be unique across all databases in a Sql Server instance (well, it should be unique globally, but Sql Server doesn't have a way to enforce that). When you restore a database, you have an option of disabling Service Broker in the restored database, enabling it with the GUID of the backed up database (so that it can take over message processing from the backed up database) or assign it a new GUID. You're trying to do the second option while you still have the old database around and you run into GUID conflict.
See here for more info.
Run this query to find out which other databases are using the same service broker as the database you are using (e.g. for a database called DATABASE_NAME)...
SELECT name, is_broker_enabled, service_broker_guid FROM sys.databases
WHERE service_broker_guid IN (SELECT service_broker_guid FROM sys.databases where name = 'DATABASE_NAME');
... returns ...
name, is_broker_enabled, service_broker_guid
DATABASE_NAME_OTHER, 1, KBHDBVJH-SDVHIOHD-SODIVDIOH-UHDSV
DATABASE_NAME_ANOTHER, 0, KBHDBVJH-SDVHIOHD-SODIVDIOH-UHDSV
DATABASE_NAME, 0, KBHDBVJH-SDVHIOHD-SODIVDIOH-UHDSV
Then run the following queries to obtain a new broker for your database...
ALTER DATABASE DATABASE_NAME SET SINGLE_USER WITH ROLLBACK IMMEDIATE;
ALTER DATABASE DATABASE_NAME SET NEW_BROKER;
ALTER DATABASE DATABASE_NAME SET MULTI_USER;
Run the first query again and your database should be the only one in the list...
SELECT name, is_broker_enabled, service_broker_guid FROM sys.databases
WHERE service_broker_guid IN (SELECT service_broker_guid FROM sys.databases where name = 'DATABASE_NAME');
... now returns ...
name, is_broker_enabled, service_broker_guid
DATABASE_NAME, 1, ASJCBUHBC-7UIOSUI-IUGGUI87-IUGHUIG
I found a very simple solution for that- just simlpy assign new service broker, like this:
public void TurnOnBroker()
{
if (!this.database.BrokerEnabled)
{
this.server.KillAllProcesses(this.database.Name);
string brokerCommand = String.Format("ALTER DATABASE {0} SET NEW_BROKER", this.database.Name);
this.database.ExecuteNonQuery(brokerCommand);
RefreshConnection();
}
}

How do you kill all current connections to a SQL Server 2005 database?

I want to rename a database, but keep getting the error that 'couldn't get exclusive lock' on the database, which implies there is some connection(s) still active.
How can I kill all the connections to the database so that I can rename it?
The reason that the approach that Adam suggested won't work is that during the time that you are looping over the active connections new one can be established, and you'll miss those. You could instead use the following approach which does not have this drawback:
-- set your current connection to use master otherwise you might get an error
use master
ALTER DATABASE YourDatabase SET SINGLE_USER WITH ROLLBACK IMMEDIATE
--do you stuff here
ALTER DATABASE YourDatabase SET MULTI_USER
Script to accomplish this, replace 'DB_NAME' with the database to kill all connections to:
USE master
GO
SET NOCOUNT ON
DECLARE #DBName varchar(50)
DECLARE #spidstr varchar(8000)
DECLARE #ConnKilled smallint
SET #ConnKilled=0
SET #spidstr = ''
Set #DBName = 'DB_NAME'
IF db_id(#DBName) < 4
BEGIN
PRINT 'Connections to system databases cannot be killed'
RETURN
END
SELECT #spidstr=coalesce(#spidstr,',' )+'kill '+convert(varchar, spid)+ '; '
FROM master..sysprocesses WHERE dbid=db_id(#DBName)
IF LEN(#spidstr) > 0
BEGIN
EXEC(#spidstr)
SELECT #ConnKilled = COUNT(1)
FROM master..sysprocesses WHERE dbid=db_id(#DBName)
END
Kill it, and kill it with fire:
USE master
go
DECLARE #dbname sysname
SET #dbname = 'yourdbname'
DECLARE #spid int
SELECT #spid = min(spid) from master.dbo.sysprocesses where dbid = db_id(#dbname)
WHILE #spid IS NOT NULL
BEGIN
EXECUTE ('KILL ' + #spid)
SELECT #spid = min(spid) from master.dbo.sysprocesses where dbid = db_id(#dbname) AND spid > #spid
END
Using SQL Management Studio Express:
In the Object Explorer tree drill down under Management to "Activity Monitor" (if you cannot find it there then right click on the database server and select "Activity Monitor"). Opening the Activity Monitor, you can view all process info. You should be able to find the locks for the database you're interested in and kill those locks, which will also kill the connection.
You should be able to rename after that.
I've always used:
ALTER DATABASE DB_NAME SET SINGLE_USER WITH ROLLBACK IMMEDIATE
GO
SP_RENAMEDB 'DB_NAME','DB_NAME_NEW'
Go
ALTER DATABASE DB_NAME_NEW SET MULTI_USER -- set back to multi user
GO
ALTER DATABASE [Test]
SET OFFLINE WITH ROLLBACK IMMEDIATE
ALTER DATABASE [Test]
SET ONLINE
Take offline takes a while and sometimes I experience some problems with that..
Most solid way in my opinion:
Detach
Right click DB -> Tasks -> Detach...
check "Drop Connections"
Ok
Reattach
Right click Databases -> Attach..
Add... -> select your database, and change the Attach As column to your desired database name.
Ok
Select 'Kill '+ CAST(p.spid AS VARCHAR)KillCommand into #temp
from master.dbo.sysprocesses p (nolock)
join master..sysdatabases d (nolock) on p.dbid = d.dbid
Where d.[name] = 'your db name'
Declare #query nvarchar(max)
--Select * from #temp
Select #query =STUFF((
select ' ' + KillCommand from #temp
FOR XML PATH('')),1,1,'')
Execute sp_executesql #query
Drop table #temp
use the 'master' database and run this query, it will kill all the active connections from your database.
I usually run into that error when I am trying to restore a database I usually just go to the top of the tree in Management Studio and right click and restart the database server (because it's on a development machine, this might not be ideal in production). This is close all database connections.
In MS SQL Server Management Studio on the object explorer, right click on the database. In the context menu that follows select 'Tasks -> Take Offline'
Another "kill it with fire" approach is to just restart the MSSQLSERVER service.
I like to do stuff from the commandline. Pasting this exactly into CMD will do it:
NET STOP MSSQLSERVER & NET START MSSQLSERVER
Or open "services.msc" and find "SQL Server (MSSQLSERVER)" and right-click, select "restart".
This will "for sure, for sure" kill ALL connections to ALL databases running on that instance.
(I like this better than many approaches that change and change back the configuration on the server/database)
Here's how to reliably this sort of thing in MS SQL Server Management Studio 2008 (may work for other versions too):
In the Object Explorer Tree, right click the root database server (with the green arrow), then click activity monitor.
Open the processes tab in the activity monitor, select the 'databases' drop down menu, and filter by the database you want.
Right click the DB in Object Explorer and start a 'Tasks -> Take Offline' task. Leave this running in the background while you...
Safely shut down whatever you can.
Kill all remaining processes from the process tab.
Bring the DB back online.
Rename the DB.
Bring your service back online and point it to the new DB.
The option working for me in this scenario is as follows:
Start the "Detach" operation on the database in question. This wil open a window (in SQL 2005) displaying the active connections that prevents actions on the DB.
Kill the active connections, cancel the detach-operation.
The database should now be available for restoring.
Try this:
ALTER DATABASE [DATABASE_NAME]
SET SINGLE_USER
WITH ROLLBACK IMMEDIATE
Right click on the database name, click on Property to get property window, Open the Options tab and change the "Restrict Access" property from Multi User to Single User. When you hit on OK button, it will prompt you to closes all open connection, select "Yes" and you are set to rename the database....
These didn't work for me (SQL2008 Enterprise), I also couldn't see any running processes or users connected to the DB. Restarting the server (Right click on Sql Server in Management Studio and pick Restart) allowed me to restore the DB.
I'm using SQL Server 2008 R2, my DB was already set for single user and there was a connection that restricted any action on the database. Thus the recommended SQLMenace's solution responded with error. Here is one that worked in my case.
I use sp_who to get list of all process in database. This is better because you may want to review which process to kill.
declare #proc table(
SPID bigint,
Status nvarchar(255),
Login nvarchar(255),
HostName nvarchar(255),
BlkBy nvarchar(255),
DBName nvarchar(255),
Command nvarchar(MAX),
CPUTime bigint,
DiskIO bigint,
LastBatch nvarchar(255),
ProgramName nvarchar(255),
SPID2 bigint,
REQUESTID bigint
)
insert into #proc
exec sp_who2
select *, KillCommand = concat('kill ', SPID, ';')
from #proc
Result
You can use command in KillCommand column to kill the process you want to.
SPID KillCommand
26 kill 26;
27 kill 27;
28 kill 28;
You can Use SP_Who command and kill all process that use your database and then rename your database.

Resources