Skip to content

Commit ce3b312

Browse files
committed
Added -f "file" option.
1 parent 7e561a5 commit ce3b312

2 files changed

Lines changed: 50 additions & 14 deletions

File tree

ReadMe.md

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,15 @@ A command-line utilty that does local SQL Server backups/restores to STDOUT/STDI
88
Options:
99
-q Quiet, don't print messages to STDERR
1010
-i "instancename"
11+
-f "file" Write/read file instead of STDOUT/STDIN
1112

1213
## Examples ##
1314

1415
Basic backup:
1516

1617
sqlpipe backup AdventureWorks > AdventureWorks.bak
1718

18-
Backup with named intance SQLEXPRESS:
19+
Backup from named instance SQLEXPRESS:
1920

2021
sqlpipe backup AdventureWorks -i SQLEXPRESS > AdventureWorks.bak
2122

@@ -37,11 +38,19 @@ Restore gzip compressed database (assumes 7-Zip's 7z.exe is in `%PATH%`):
3738

3839
## Remote SQL Servers ##
3940

40-
SqlPipe itself can only connect to a local SQL Server, but by using something like Sysinternals' PSExec you can execute it remotely like so:
41+
SqlPipe itself can only connect to a local SQL Server, but by using something like [Sysinternals PSExec](http://technet.microsoft.com/en-us/sysinternals/bb897553) you can execute it remotely like so:
4142

42-
psexec \\myserver -c sqlpipe backup AdventureWorks > C:\Backups\AdventureWorks.bak
43+
psexec \\dbserver -cv sqlpipe backup AdventureWorks > C:\Backups\AdventureWorks.bak
4344

44-
Note that in this example that `C:\Backups\Inventory.bak` refers to a location on *your* machine not the remote server. Yes, the backup data was piped over the network!
45+
Note that in this example that `C:\Backups\Inventory.bak` refers to a location on *your* machine not the remote server. Yes, the backup data was piped over the network!
46+
47+
To write to a remote file locaton use the `-f` option:
48+
49+
psexec \\dbserver -cv sqlpipe backup AdventureWorks -f C:\Backups\AdventureWorks.bak
50+
51+
Or a central network location:
52+
53+
psexec \\dbserver -u domain\user -p P@55w0rd -cv sqlpipe backup AdventureWorks -f \\fileserver\Backups\AdventureWorks.bak
4554

4655
## Implementation details ##
4756

SqlPipe.cpp

Lines changed: 37 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -202,24 +202,30 @@ Action and database required.\n\
202202
Usage: sqlpipe backup|restore <database> [options]\n\
203203
Options:\n\
204204
-q Quiet, don't print messages to STDERR\n\
205-
-i instancename\n");
205+
-i \"instancename\"\n\
206+
-f \"file\" Write/read file instead of STDOUT/STDIN\n");
206207
return 1;
207208
}
208209

209-
TCHAR* command = argv[1];
210+
TCHAR* command = _wcslwr(argv[1]);
210211
TCHAR* databaseName = argv[2];
211212

213+
TCHAR* filePath = NULL;
214+
212215
// Parse options
213216
for (int i = 0; i < argc; i++)
214217
{
215-
216218
TCHAR* arg = _wcslwr(_wcsdup(argv[i]));
219+
217220
if (wcscmp(arg, L"-q") == 0)
218221
_optionQuiet = true;
219222

220223
if (wcscmp(arg, L"-i") == 0)
221224
_serverInstanceName = argv[i+1];
222225

226+
if (wcscmp(arg, L"-f") == 0)
227+
filePath = argv[i+1];
228+
223229
free(arg);
224230
}
225231

@@ -278,30 +284,51 @@ Options:\n\
278284
}
279285

280286
TCHAR* sql;
281-
FILE* backupFile;
282-
if (_wcsicmp(command, L"backup") == 0)
287+
FILE* backupFile = NULL;
288+
if (wcscmp(command, L"backup") == 0)
283289
{
284290
sql = "BACKUP DATABASE [" + _bstr_t(databaseName) + "] TO VIRTUAL_DEVICE = '" + virtualDeviceName + "'";
285-
backupFile = stdout;
291+
if (filePath == NULL)
292+
backupFile = stdout;
293+
else
294+
{
295+
backupFile = _wfopen(filePath, L"w");
296+
if (backupFile == NULL)
297+
{
298+
err(L"Error creating '%s': %s\n", filePath, _wcserror(errno));
299+
return errno;
300+
}
301+
}
286302
}
287-
else if(_wcsicmp(command, L"restore") == 0)
303+
else if(wcscmp(command, L"restore") == 0)
288304
{
289305
hr = executeSql("CREATE DATABASE ["+ _bstr_t(databaseName) +"]");
290306
if (FAILED(hr))
291307
return hr;
292308

293309
sql = "RESTORE DATABASE [" + _bstr_t(databaseName) + "] FROM VIRTUAL_DEVICE = '" + virtualDeviceName + "' WITH REPLACE";
294-
backupFile = stdin;
310+
if (filePath == NULL)
311+
backupFile = stdin;
312+
else
313+
{
314+
backupFile = _wfopen(filePath, L"r");
315+
if (backupFile == NULL)
316+
{
317+
err(L"Error opening '%s': %s\n", filePath, _wcserror(errno));
318+
return errno;
319+
}
320+
}
295321
}
296322
else
297323
{
298324
err(L"Unsupported command '%s': only BACKUP or RESTORE are supported.\n", command);
299325
return 1;
300326
}
301327

328+
302329
// Invoke backup on separate thread because virtualDeviceSet->GetConfiguration will block until "BACKUP DATABASE..."
303330
DWORD threadId;
304-
HANDLE executeSqlThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)&executeSql, (TCHAR*)sql, 0, &threadId);
331+
HANDLE executeSqlThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)&executeSql, sql, 0, &threadId);
305332

306333
// Ready...
307334
hr = virtualDeviceSet->GetConfiguration(30000, &vdConfig);
@@ -329,7 +356,7 @@ Options:\n\
329356
}
330357

331358
// Go
332-
_setmode(_fileno(backupFile), _O_BINARY);
359+
_setmode(_fileno(backupFile), _O_BINARY); //ensure \n's in STDOUT don't get tampered with
333360
hr = performTransfer(virtualDevice, backupFile);
334361

335362
WaitForSingleObject(executeSqlThread, 5000);

0 commit comments

Comments
 (0)