Localdb linked servers - sql

I'm trying to replicate a production environment locally and the production database uses a linked server. I've been able to create multiple instances of localdb; is it possible to create a linkedserver between localdb instances? If not, what other options do I have available (ideally without having to use a full sql instance).

Not sure if it's bad form to answer your own question but in case anyone else has the same issue in the future, it turns out it is possible and pretty straight forward. Once you've created your new instance of localdb, use this:
USE master
IF EXISTS(SELECT * from sys.servers WHERE name = N'{serverName}')
BEGIN
DECLARE #serverId INT
SELECT #serverId = server_id FROM sys.servers WHERE name = N'{serverName}'
IF EXISTS(SELECT * FROM sys.linked_logins WHERE server_id = #serverId)
BEGIN
EXEC sp_droplinkedsrvlogin '{serverName}', null
END
EXEC sp_dropserver '{serverName}'
END
EXEC sp_addlinkedserver
#server=N'{serverName}',
#provider=N'SQLNCLI',
#srvproduct=N'',
#datasrc=N'{dataSource}';
EXEC sp_addlinkedsrvlogin
#rmtsrvname=N'{serverName}',
#useself='true'

To expand on Dave's auto-answer a little...
If the remote database has not been attached to its instance yet, it will be necessary to include additional connection details in the Provider String argument of sp_addlinked server.
EXEC sp_addlinkedserver
#server=N'{serverName}',
#provider=N'SQLNCLI',
#srvproduct=N'',
#datasrc=N'{dataSource}'
#provstr=N'{providerString}';
In my case I used:
{dataSource} = (LocalDB)\MSSQLLocalDB
{providerString} = AttachDbFileName=C:\Temp\Test.mdf;Integrated Security=True

Related

SQL: How to conditionally define the code that contains linked server ID only for some server instances?

I am writing a data pump as a stored procedure on SQL Server. It is expected to extract some data from Sybase, and UPDATE or INSERT the table in SQL Server database.
For development, the source table is stored in the test database on the same SQL Server as the target table is (in different database). On the production site, the Sybase server is connected as a linked server.
How can write common code (for the installation script) that would work both on the testing site, and on the production site?
See the fragment... and the details below:
CREATE PROCEDURE dbo.sp_data_pump
AS
BEGIN
SET NOCOUNT ON
IF ##servername = 'COMPUTER\SQLTESTINSTANCE' BEGIN
-- for development
MERGE dbo.sometable AS tar
USING (SELECT code, data
FROM dbtest.dbo.datapump_sometable) AS source -- !!!!
ON tar.code = source.code
WHEN MATCHED THEN
UPDATE
SET tar.data = source.data,
tar.changed = GETDATE(),
tar.changedby = 'datapump'
WHEN NOT MATCHED THEN
INSERT (data, created, createdby)
VALUES (source.code, source.data, GETDATE(), 'datapump');
END ELSE BEGIN
-- for the deployed application
MERGE dbo.sometable AS tar
USING (SELECT data
FROM OPENQUERY(LINKEDSRVID, 'SELECT * FROM xdb.schema.xxx_sometable')) AS source -- !!!!
ON tar.code = source.code
WHEN MATCHED THEN
WHEN MATCHED THEN
UPDATE
SET tar.data = source.data,
tar.changed = GETDATE(),
tar.changedby = 'datapump'
WHEN NOT MATCHED THEN
INSERT (data, created, createdby)
VALUES (source.code, source.data, GETDATE(), 'datapump');
END
END
The Sybase database contains a view to access the data; however, the view can be called only through OPENQUERY(LINKEDSRVID, 'SELECT ....'). Because of this, the LINKEDSRVID must exist. However, it is not created on the development site, therefore the code does not compile.
The core of the problem can be simplified to pseudo code:
CREATE PROCEDURE dbo.sp_data_pump
AS
BEGIN
IF ##servername = 'COMPUTER\SQLTESTINSTANCE' BEGIN
-- for development
...
SELECT * FROM dbtest.dbo.datapump_sometable) AS source
...
END ELSE BEGIN
-- for the deployed application
...
SELECT * FROM OPENQUERY(LINKEDSRVID, 'SELECT * FROM xdb.schema.xxx_sometable')) AS source
...
END
END
How the problem should be solved?
It sounds like you just need to create a fake linked server in your dev environment to imitate live... You can do this by creating a linked server connection using the SQL Native drivers which can have any name but set the source to localhost. The link is just to itself and not functional, just there for development.
Eg;
EXEC master.dbo.sp_addlinkedserver
#server = N'LiveServerName',
#srvproduct=N'',
#provider=N'SQLNCLI',
#datasrc=N'localhost' --just to imitate the connection
Also create the database and other tables/objects on localhost for the sake of validation of the 4 part "remote" reference.
Hope that makes sense.
Although you could wrap the code in dynamic SQL to avoid the compile error, I suggest you create a linked server named LINKEDSRVID in dev and just include OPENQUERY in the proc. Ideally, that should point to a test Sybase instance but you could create one for the dbtest database instead if that's not an option. Just be aware that testing won't be totally valid if you don't have a Sybase test instance.

Calling xp_cmdshell from a Stored Procedure

As a proof of concept we're trying to insert an xp_cmdshell command into an existing solution. Currently an application invokes a stored procedure on our database server which when profiled looks like:
declare #P1 int
set #P1=1
exec Name_Of_The_SP #param1 = 3, #param2 = 'blah', #parametc = 'blahetc', #ID = P1 output
select #P1
The SP essentially opens a transaction, inserts a row, and then commits. Inside this we added:
exec master..xp_cmdshell 'dir > c:\test.txt'
When we then run the first block of code in a SSMS query window the file is generated on the server as expected. But when we use the application to invoke it then the rows are inserted as normal but the file isn't generated?
The SQL Server and SQLAgent users are local admins and sysadmins so can't see any issues there. Tried making the application user a local admin also, to no avail, it was already a sysadmin.
This is SQL Server 2000
We managed to figure this out - we (I) were overlooking in profiler that the exec was coming in under a different login. Granting execute permission to master.dbo.xp_cmdshell specifically got it working. Apologies to anyone who spent any time/effort on this!

One-line alternative for xp_cmdshell? I tried several things

Hello Microsoft SQL Server Masters,
Well, I have an Microsoft SQL Server 2000 as described below:
Microsoft SQL Server 2000 - 8.00.2039 (Intel X86)
May 3 2005 23:18:38
Copyright (c) 1988-2003 Microsoft Corporation
Desktop Engine on Windows NT 5.2 (Build 3790: Service Pack 2)
I need to execute an Operating System command from this Microsoft SQL Server, I checked that I have sysadmin privileges with the query below and it returned "1", which confirm my privilege.
SELECT IS_SRVROLEMEMBER('sysadmin', 'sa');
I tried the traditional xp_cmdshell and nothing happened, just to make sure it was working I tried the famous:
EXEC xp_cmdshell 'dir c:\'; EXEC master.dbo.xp_cmdshell 'dir c:\';
EXEC master..xp_cmdshell "dir c:\";
And all returned NOTHING, which make me believe that xp_cmdshell is not available. I know that xp_cmdshell comes disable by default in Microsoft SQL Server 2005, but not in 2000, anyway, I tried to reenable it on the same way but it failed.
I looked at internet and I found this way to reenable xp_cmdshell for Microsoft SQL Server 2000:
exec sp_addextendedproc 'xp_cmdshell', 'xplog70.dll'
exec sp_addextendedproc xp_cmdshell, 'C:\Program Files\Microsoft SQL Server\MSSQL\Binn\xplog70.dll'
However, it still doesn't work. I found another article telling that sometimes admins delete this files and I think it may be my case, the article says that if it was deleted I can execute "xp_msver" and in my case it also return nothing.
Reference: http://support.microsoft.com/kb/891984
I also tried this query that I found on the internet to see if xp_cmdshell exist and it returned nothing (but it may be a limitation of my weird SQL client, see below please).
if exists (select * from dbo.sysobjects where id = object_id(N’[dbo].[ xp_cmdshell]‘) and OBJECTPROPERTY(id, N’IsExtendedProc’) = 1);
So, I'm really in trouble, I researched at Google and found potential solutions such as Job agent, SSIS package, CLR stored procedure, sp_OACreate (and friends) and SQLCMD but nothing worked. Maybe I did it incorrect, but another limitation in my case is that I just have access to this Microsoft SQL Server 2000 from a jump-box (Linux) that has a very odd sql-server client that do not accept queries with multiple lines, consequently I can't try with success the following potential solutions:
1# Job Agent
DECLARE #jobID uniqueidentifier, #cmd varchar(1000)
SET #cmd = 'netstat -na > c:\connections.txt'
EXEC msdb.dbo.sp_add_job #job_name = '_tmp_MakeDirectory', #enabled = 1, #start_step_id = 1, #owner_login_name='sa', #job_id = #jobID OUTPUT
EXEC msdb.dbo.sp_add_jobstep #job_id = #jobID, #step_name = 'Create Backup Folder', #step_id = 1, #subsystem = 'CMDEXEC', #command = #cmd
EXEC msdb.dbo.sp_add_jobserver #job_id = #jobID
EXEC msdb.dbo.sp_start_job #job_id = #jobID, #output_flag = 0
WAITFOR DELAY '000:00:05' -- Give the job a chance to complete
IF EXISTS (SELECT name FROM msdb.dbo.sysjobs WHERE name = '_tmp_MakeDirectory')
BEGIN
EXEC msdb.dbo.sp_delete_job #job_name = '_tmp_MakeDirectory'
END
2# SQLCMD
CREATE PROCEDURE SQLCMD_TEST
AS
!!MKDIR "netstat -na > c:\connections.txt"
:OUT "C:\TEST\test.TXT"
SELECT ##VERSION AS 'SERVER VERSION'
!!DIR
GO
SELECT ##SERVERNAME AS 'SERVER NAME'
GO
EXEC SQLCMD_TEST
Unfortunately I don't have any other way to access this Microsoft SQL Server, I know it's not the best way, but it's how it's and I can't do anything. So, I need a solution to execute Operating System commands on this Microsoft SQL Server 2000 with all this limitations. Can someone port any of the two above methods for one single line query, please?
Any other suggestion with example is very welcome.
Thanks a lot.
Regards.
I used to use xp_cmdshell before CLR support came along. Unfortunately, you are a version away from CLR support (SQL Server 2005) and the system.io namespace. You can, however, create your own extended stored procedures which can access the file system and create directories. See here for more info: http://www.devarticles.com/c/a/SQL-Server/Extended-Stored-Procedures-Intro-And-10-Cool-Examples/
By the way, xp_cmdshell is an extended stored procedure.

xp_cmdshell copy command seldom fails

I am running SQL Server 2005 on Windows Server 2003 machine.
I have a requirement to accumulate small text files into a bigger one.
So I use
exec xp_cmdshell #sql
where #sql=
'copy /b'+#sourcePath+#sourceFile+' '+#destinationPath+#NewFileName
Both the source and destination paths are on a separate server.
Seldom this process fails and I don't find anything else in the event or SQL Server logs.
The Surface Area Config for xp_cmdshell is also enabled.
Please help.....
I just tested this on my sql server 2005 and EXEC dbo.xp_cmdshell always returns output (even in the case of a bogus command) in the form of a table. For C#, if you call this code with ExecuteNonQuery, then call it with ExecuteReader and read the output. Alternatively, you could dump the output in a table so that you can look at it later at your leisure. Create a table like this :
CREATE TABLE [dbo].[xp_cmdShellOutput](
[errorMsg] [nvarchar](max) NULL
)
and then use this code :
DECLARE #sql AS VARCHAR(600)
SELECT #sql = '<your command>'
INSERT dbo.xp_cmdShellOutput(errorMsg)
EXEC dbo.xp_cmdshell #sql

Delete All SQL Server Linked Servers on single server

Im using SQL Server Management Studio 2008 (ssms.exe) connected with a local SQL Server 2000, so I notice that every time I try enter on Linked Server option It crash inmediatly so I want to delete all the servers linkeds there for try again.
What script should I use or what command on T-SQL I have to run for delete all and without specifying the name of each server linked.
Thanks
You can execute sp_dropserver for all linked servers using the database cursor. The following example shows how to do this.
DECLARE #sql NVARCHAR(MAX)
DECLARE db_cursor CURSOR FOR
select 'sp_dropserver ''' + [name] + '''' from sys.servers
OPEN db_cursor
FETCH NEXT FROM db_cursor INTO #sql
WHILE ##FETCH_STATUS = 0
BEGIN
EXEC (#sql)
FETCH NEXT FROM db_cursor INTO #sql
END
CLOSE db_cursor
DEALLOCATE db_cursor
I think you can only delete on linked server at a time, using sp_dropserver:
http://msdn.microsoft.com/en-us/library/ms174310.aspx
You could call sp_linkedservers
http://msdn.microsoft.com/en-us/library/ms189519.aspx
reading the returned list into a temporary table, and then loop through that table, calling sp_dropserver for each element.
While connected to the server:
select 'exec sp_dropServer ''' + name + '''', * from sys.servers where is_linked = 1
run the outputted first column. win.
This also allows you to pick and choose which server you want to get rid of. It is probably hanging on the connection, getting garbage it doesn't know how to handle back from a server, or a corrupted link driver.
You can't just arbitrarily delete all the linked servers from every server. You'll have to (at a minimum) open a connection to each server and run some form of script or command for each linked server. If you want to know how to write a script to drop all linked servers, I suggest that you start by looking at sp_linkedservers and sp_dropserver.
Do you get any error message when it is crashing?
Also what is the service pack of that corresponding SQL 2000 server?
I would rather fix this tools issue than simply recreating them a fresh.
Version without a cursor. server_id=0 is the local server not a linked server.
--remove all linked servers
declare #sql nvarchar(max)
while exists (select 1 from sys.servers where server_id>0)
begin
select #sql= N'sp_dropserver ' + [name] from sys.servers where server_id>0
exec (#sql)
end