diff options
Diffstat (limited to 'src/libs/dutil/WixToolset.DUtil/sqlutil.cpp')
-rw-r--r-- | src/libs/dutil/WixToolset.DUtil/sqlutil.cpp | 1002 |
1 files changed, 1002 insertions, 0 deletions
diff --git a/src/libs/dutil/WixToolset.DUtil/sqlutil.cpp b/src/libs/dutil/WixToolset.DUtil/sqlutil.cpp new file mode 100644 index 00000000..782c7088 --- /dev/null +++ b/src/libs/dutil/WixToolset.DUtil/sqlutil.cpp | |||
@@ -0,0 +1,1002 @@ | |||
1 | // Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. | ||
2 | |||
3 | #include "precomp.h" | ||
4 | |||
5 | // okay, this may look a little weird, but sqlutil.h cannot be in the | ||
6 | // pre-compiled header because we need to #define these things so the | ||
7 | // correct GUID's get pulled into this object file | ||
8 | #include <initguid.h> | ||
9 | #define DBINITCONSTANTS | ||
10 | #include "sqlutil.h" | ||
11 | |||
12 | |||
13 | //Please note that only SQL native client 11 has TLS1.2 support | ||
14 | #define _SQLNCLI_OLEDB_DEPRECATE_WARNING | ||
15 | |||
16 | #if !defined(SQLNCLI_VER) | ||
17 | #define SQLNCLI_VER 1100 | ||
18 | #endif | ||
19 | |||
20 | #if SQLNCLI_VER >= 1100 | ||
21 | #if defined(_SQLNCLI_OLEDB_) || !defined(_SQLNCLI_ODBC_) | ||
22 | #define SQLNCLI_CLSID CLSID_SQLNCLI11 | ||
23 | #endif // defined(_SQLNCLI_OLEDB_) || !defined(_SQLNCLI_ODBC_) | ||
24 | extern const GUID OLEDBDECLSPEC _SQLNCLI_OLEDB_DEPRECATE_WARNING CLSID_SQLNCLI11 = { 0x397C2819L,0x8272,0x4532,{ 0xAD,0x3A,0xFB,0x5E,0x43,0xBE,0xAA,0x39 } }; | ||
25 | #endif // SQLNCLI_VER >= 1100 | ||
26 | |||
27 | // Exit macros | ||
28 | #define SqlExitTrace(x, s, ...) ExitTraceSource(DUTIL_SOURCE_SQLUTIL, x, s, __VA_ARGS__) | ||
29 | #define SqlExitOnLastError(x, s, ...) ExitOnLastErrorSource(DUTIL_SOURCE_SQLUTIL, x, s, __VA_ARGS__) | ||
30 | #define SqlExitOnLastErrorDebugTrace(x, s, ...) ExitOnLastErrorDebugTraceSource(DUTIL_SOURCE_SQLUTIL, x, s, __VA_ARGS__) | ||
31 | #define SqlExitWithLastError(x, s, ...) ExitWithLastErrorSource(DUTIL_SOURCE_SQLUTIL, x, s, __VA_ARGS__) | ||
32 | #define SqlExitOnFailure(x, s, ...) ExitOnFailureSource(DUTIL_SOURCE_SQLUTIL, x, s, __VA_ARGS__) | ||
33 | #define SqlExitOnRootFailure(x, s, ...) ExitOnRootFailureSource(DUTIL_SOURCE_SQLUTIL, x, s, __VA_ARGS__) | ||
34 | #define SqlExitOnFailureDebugTrace(x, s, ...) ExitOnFailureDebugTraceSource(DUTIL_SOURCE_SQLUTIL, x, s, __VA_ARGS__) | ||
35 | #define SqlExitOnNull(p, x, e, s, ...) ExitOnNullSource(DUTIL_SOURCE_SQLUTIL, p, x, e, s, __VA_ARGS__) | ||
36 | #define SqlExitOnNullWithLastError(p, x, s, ...) ExitOnNullWithLastErrorSource(DUTIL_SOURCE_SQLUTIL, p, x, s, __VA_ARGS__) | ||
37 | #define SqlExitOnNullDebugTrace(p, x, e, s, ...) ExitOnNullDebugTraceSource(DUTIL_SOURCE_SQLUTIL, p, x, e, s, __VA_ARGS__) | ||
38 | #define SqlExitOnInvalidHandleWithLastError(p, x, s, ...) ExitOnInvalidHandleWithLastErrorSource(DUTIL_SOURCE_SQLUTIL, p, x, s, __VA_ARGS__) | ||
39 | #define SqlExitOnWin32Error(e, x, s, ...) ExitOnWin32ErrorSource(DUTIL_SOURCE_SQLUTIL, e, x, s, __VA_ARGS__) | ||
40 | #define SqlExitOnGdipFailure(g, x, s, ...) ExitOnGdipFailureSource(DUTIL_SOURCE_SQLUTIL, g, x, s, __VA_ARGS__) | ||
41 | |||
42 | // private prototypes | ||
43 | static HRESULT InitializeDatabaseConnection( | ||
44 | __in REFCLSID rclsid, | ||
45 | __in_z LPCSTR szFriendlyClsidName, | ||
46 | __in DBPROPSET rgdbpsetInit[], | ||
47 | __in_ecount(rgdbpsetInit) DWORD cdbpsetInit, | ||
48 | __out IDBCreateSession** ppidbSession | ||
49 | ); | ||
50 | HRESULT DumpErrorRecords(); | ||
51 | static HRESULT FileSpecToString( | ||
52 | __in const SQL_FILESPEC* psf, | ||
53 | __out LPWSTR* ppwz | ||
54 | ); | ||
55 | static HRESULT EscapeSqlIdentifier( | ||
56 | __in_z LPCWSTR wzDatabase, | ||
57 | __deref_out_z LPWSTR* ppwz | ||
58 | ); | ||
59 | |||
60 | |||
61 | /******************************************************************** | ||
62 | SqlConnectDatabase - establishes a connection to a database | ||
63 | |||
64 | NOTE: wzInstance is optional | ||
65 | if fIntegratedAuth is set then wzUser and wzPassword are ignored | ||
66 | ********************************************************************/ | ||
67 | extern "C" HRESULT DAPI SqlConnectDatabase( | ||
68 | __in_z LPCWSTR wzServer, | ||
69 | __in_z LPCWSTR wzInstance, | ||
70 | __in_z LPCWSTR wzDatabase, | ||
71 | __in BOOL fIntegratedAuth, | ||
72 | __in_z LPCWSTR wzUser, | ||
73 | __in_z LPCWSTR wzPassword, | ||
74 | __out IDBCreateSession** ppidbSession | ||
75 | ) | ||
76 | { | ||
77 | Assert(wzServer && wzDatabase && *wzDatabase && ppidbSession); | ||
78 | |||
79 | HRESULT hr = S_OK; | ||
80 | LPWSTR pwzServerInstance = NULL; | ||
81 | DBPROP rgdbpInit[4] = { }; | ||
82 | DBPROPSET rgdbpsetInit[1] = { }; | ||
83 | ULONG cProperties = 0; | ||
84 | |||
85 | // if there is an instance | ||
86 | if (wzInstance && *wzInstance) | ||
87 | { | ||
88 | hr = StrAllocFormatted(&pwzServerInstance, L"%s\\%s", wzServer, wzInstance); | ||
89 | } | ||
90 | else | ||
91 | { | ||
92 | hr = StrAllocString(&pwzServerInstance, wzServer, 0); | ||
93 | } | ||
94 | SqlExitOnFailure(hr, "failed to allocate memory for the server instance"); | ||
95 | |||
96 | // server[\instance] | ||
97 | rgdbpInit[cProperties].dwPropertyID = DBPROP_INIT_DATASOURCE; | ||
98 | rgdbpInit[cProperties].dwOptions = DBPROPOPTIONS_REQUIRED; | ||
99 | rgdbpInit[cProperties].colid = DB_NULLID; | ||
100 | ::VariantInit(&rgdbpInit[cProperties].vValue); | ||
101 | rgdbpInit[cProperties].vValue.vt = VT_BSTR; | ||
102 | rgdbpInit[cProperties].vValue.bstrVal = ::SysAllocString(pwzServerInstance); | ||
103 | ++cProperties; | ||
104 | |||
105 | // database | ||
106 | rgdbpInit[cProperties].dwPropertyID = DBPROP_INIT_CATALOG; | ||
107 | rgdbpInit[cProperties].dwOptions = DBPROPOPTIONS_REQUIRED; | ||
108 | rgdbpInit[cProperties].colid = DB_NULLID; | ||
109 | ::VariantInit(&rgdbpInit[cProperties].vValue); | ||
110 | rgdbpInit[cProperties].vValue.vt = VT_BSTR; | ||
111 | rgdbpInit[cProperties].vValue.bstrVal= ::SysAllocString(wzDatabase); | ||
112 | ++cProperties; | ||
113 | |||
114 | if (fIntegratedAuth) | ||
115 | { | ||
116 | // username | ||
117 | rgdbpInit[cProperties].dwPropertyID = DBPROP_AUTH_INTEGRATED; | ||
118 | rgdbpInit[cProperties].dwOptions = DBPROPOPTIONS_REQUIRED; | ||
119 | rgdbpInit[cProperties].colid = DB_NULLID; | ||
120 | ::VariantInit(&rgdbpInit[cProperties].vValue); | ||
121 | rgdbpInit[cProperties].vValue.vt = VT_BSTR; | ||
122 | rgdbpInit[cProperties].vValue.bstrVal = ::SysAllocString(L"SSPI"); // default windows authentication | ||
123 | ++cProperties; | ||
124 | } | ||
125 | else | ||
126 | { | ||
127 | // username | ||
128 | rgdbpInit[cProperties].dwPropertyID = DBPROP_AUTH_USERID; | ||
129 | rgdbpInit[cProperties].dwOptions = DBPROPOPTIONS_REQUIRED; | ||
130 | rgdbpInit[cProperties].colid = DB_NULLID; | ||
131 | ::VariantInit(&rgdbpInit[cProperties].vValue); | ||
132 | rgdbpInit[cProperties].vValue.vt = VT_BSTR; | ||
133 | rgdbpInit[cProperties].vValue.bstrVal = ::SysAllocString(wzUser); | ||
134 | ++cProperties; | ||
135 | |||
136 | // password | ||
137 | rgdbpInit[cProperties].dwPropertyID = DBPROP_AUTH_PASSWORD; | ||
138 | rgdbpInit[cProperties].dwOptions = DBPROPOPTIONS_REQUIRED; | ||
139 | rgdbpInit[cProperties].colid = DB_NULLID; | ||
140 | ::VariantInit(&rgdbpInit[cProperties].vValue); | ||
141 | rgdbpInit[cProperties].vValue.vt = VT_BSTR; | ||
142 | rgdbpInit[cProperties].vValue.bstrVal = ::SysAllocString(wzPassword); | ||
143 | ++cProperties; | ||
144 | } | ||
145 | |||
146 | // put the properties into a set | ||
147 | rgdbpsetInit[0].guidPropertySet = DBPROPSET_DBINIT; | ||
148 | rgdbpsetInit[0].rgProperties = rgdbpInit; | ||
149 | rgdbpsetInit[0].cProperties = cProperties; | ||
150 | |||
151 | // obtain access to the SQL Native Client provider | ||
152 | hr = InitializeDatabaseConnection(SQLNCLI_CLSID, "SQL Native Client", rgdbpsetInit, countof(rgdbpsetInit), ppidbSession); | ||
153 | if (FAILED(hr)) | ||
154 | { | ||
155 | SqlExitTrace(hr, "Could not initialize SQL Native Client, falling back to SQL OLE DB..."); | ||
156 | |||
157 | // try OLE DB but if that fails return original error failure | ||
158 | HRESULT hr2 = InitializeDatabaseConnection(CLSID_SQLOLEDB, "SQL OLE DB", rgdbpsetInit, countof(rgdbpsetInit), ppidbSession); | ||
159 | if (FAILED(hr2)) | ||
160 | { | ||
161 | SqlExitTrace(hr2, "Could not initialize SQL OLE DB either, giving up."); | ||
162 | } | ||
163 | else | ||
164 | { | ||
165 | hr = S_OK; | ||
166 | } | ||
167 | } | ||
168 | |||
169 | LExit: | ||
170 | for (; 0 < cProperties; cProperties--) | ||
171 | { | ||
172 | ::VariantClear(&rgdbpInit[cProperties - 1].vValue); | ||
173 | } | ||
174 | |||
175 | ReleaseStr(pwzServerInstance); | ||
176 | |||
177 | return hr; | ||
178 | } | ||
179 | |||
180 | |||
181 | /******************************************************************** | ||
182 | SqlStartTransaction - Starts a new transaction that must be ended | ||
183 | |||
184 | *********************************************************************/ | ||
185 | extern "C" HRESULT DAPI SqlStartTransaction( | ||
186 | __in IDBCreateSession* pidbSession, | ||
187 | __out IDBCreateCommand** ppidbCommand, | ||
188 | __out ITransaction** ppit | ||
189 | ) | ||
190 | { | ||
191 | Assert(pidbSession && ppit); | ||
192 | |||
193 | HRESULT hr = S_OK; | ||
194 | |||
195 | hr = pidbSession->CreateSession(NULL, IID_IDBCreateCommand, (IUnknown**)ppidbCommand); | ||
196 | SqlExitOnFailure(hr, "unable to create command from session"); | ||
197 | |||
198 | hr = (*ppidbCommand)->QueryInterface(IID_ITransactionLocal, (LPVOID*)ppit); | ||
199 | SqlExitOnFailure(hr, "Unable to QueryInterface session to get ITransactionLocal"); | ||
200 | |||
201 | hr = ((ITransactionLocal*)*ppit)->StartTransaction(ISOLATIONLEVEL_SERIALIZABLE, 0, NULL, NULL); | ||
202 | |||
203 | LExit: | ||
204 | |||
205 | return hr; | ||
206 | } | ||
207 | |||
208 | /******************************************************************** | ||
209 | SqlEndTransaction - Ends the transaction | ||
210 | |||
211 | NOTE: if fCommit, will commit the transaction, otherwise rolls back | ||
212 | *********************************************************************/ | ||
213 | extern "C" HRESULT DAPI SqlEndTransaction( | ||
214 | __in ITransaction* pit, | ||
215 | __in BOOL fCommit | ||
216 | ) | ||
217 | { | ||
218 | Assert(pit); | ||
219 | |||
220 | HRESULT hr = S_OK; | ||
221 | |||
222 | if (fCommit) | ||
223 | { | ||
224 | hr = pit->Commit(FALSE, XACTTC_SYNC, 0); | ||
225 | SqlExitOnFailure(hr, "commit of transaction failed"); | ||
226 | } | ||
227 | else | ||
228 | { | ||
229 | hr = pit->Abort(NULL, FALSE, FALSE); | ||
230 | SqlExitOnFailure(hr, "abort of transaction failed"); | ||
231 | } | ||
232 | |||
233 | LExit: | ||
234 | |||
235 | return hr; | ||
236 | } | ||
237 | |||
238 | |||
239 | /******************************************************************** | ||
240 | SqlDatabaseExists - determines if database exists | ||
241 | |||
242 | NOTE: wzInstance is optional | ||
243 | if fIntegratedAuth is set then wzUser and wzPassword are ignored | ||
244 | returns S_OK if database exist | ||
245 | returns S_FALSE if database does not exist | ||
246 | returns E_* on error | ||
247 | ********************************************************************/ | ||
248 | extern "C" HRESULT DAPI SqlDatabaseExists( | ||
249 | __in_z LPCWSTR wzServer, | ||
250 | __in_z LPCWSTR wzInstance, | ||
251 | __in_z LPCWSTR wzDatabase, | ||
252 | __in BOOL fIntegratedAuth, | ||
253 | __in_z LPCWSTR wzUser, | ||
254 | __in_z LPCWSTR wzPassword, | ||
255 | __out_opt BSTR* pbstrErrorDescription | ||
256 | ) | ||
257 | { | ||
258 | Assert(wzServer && wzDatabase && *wzDatabase); | ||
259 | |||
260 | HRESULT hr = S_OK; | ||
261 | IDBCreateSession* pidbSession = NULL; | ||
262 | |||
263 | hr = SqlConnectDatabase(wzServer, wzInstance, L"master", fIntegratedAuth, wzUser, wzPassword, &pidbSession); | ||
264 | SqlExitOnFailure(hr, "failed to connect to 'master' database on server %ls", wzServer); | ||
265 | |||
266 | hr = SqlSessionDatabaseExists(pidbSession, wzDatabase, pbstrErrorDescription); | ||
267 | |||
268 | LExit: | ||
269 | ReleaseObject(pidbSession); | ||
270 | |||
271 | return hr; | ||
272 | } | ||
273 | |||
274 | |||
275 | /******************************************************************** | ||
276 | SqlSessionDatabaseExists - determines if database exists | ||
277 | |||
278 | NOTE: pidbSession must be connected to master database | ||
279 | returns S_OK if database exist | ||
280 | returns S_FALSE if database does not exist | ||
281 | returns E_* on error | ||
282 | ********************************************************************/ | ||
283 | extern "C" HRESULT DAPI SqlSessionDatabaseExists( | ||
284 | __in IDBCreateSession* pidbSession, | ||
285 | __in_z LPCWSTR wzDatabase, | ||
286 | __out_opt BSTR* pbstrErrorDescription | ||
287 | ) | ||
288 | { | ||
289 | Assert(pidbSession && wzDatabase && *wzDatabase); | ||
290 | |||
291 | HRESULT hr = S_OK; | ||
292 | |||
293 | LPWSTR pwzQuery = NULL; | ||
294 | IRowset* pirs = NULL; | ||
295 | |||
296 | DBCOUNTITEM cRows = 0; | ||
297 | HROW rghRows[1]; | ||
298 | HROW* prow = rghRows; | ||
299 | |||
300 | // | ||
301 | // query to see if the database exists | ||
302 | // | ||
303 | hr = StrAllocFormatted(&pwzQuery, L"SELECT name FROM sysdatabases WHERE name='%s'", wzDatabase); | ||
304 | SqlExitOnFailure(hr, "failed to allocate query string to ensure database exists"); | ||
305 | |||
306 | hr = SqlSessionExecuteQuery(pidbSession, pwzQuery, &pirs, NULL, pbstrErrorDescription); | ||
307 | SqlExitOnFailure(hr, "failed to get database list from 'master' database"); | ||
308 | Assert(pirs); | ||
309 | |||
310 | // | ||
311 | // check to see if the database was returned | ||
312 | // | ||
313 | hr = pirs->GetNextRows(DB_NULL_HCHAPTER, 0, 1, &cRows, &prow); | ||
314 | SqlExitOnFailure(hr, "failed to get row with database name"); | ||
315 | |||
316 | // succeeded but no database | ||
317 | if ((DB_S_ENDOFROWSET == hr) || (0 == cRows)) | ||
318 | { | ||
319 | hr = S_FALSE; | ||
320 | } | ||
321 | |||
322 | LExit: | ||
323 | ReleaseObject(pirs); | ||
324 | ReleaseStr(pwzQuery); | ||
325 | |||
326 | return hr; | ||
327 | } | ||
328 | |||
329 | |||
330 | /******************************************************************** | ||
331 | SqlDatabaseEnsureExists - creates a database if it does not exist | ||
332 | |||
333 | NOTE: wzInstance is optional | ||
334 | if fIntegratedAuth is set then wzUser and wzPassword are ignored | ||
335 | ********************************************************************/ | ||
336 | extern "C" HRESULT DAPI SqlDatabaseEnsureExists( | ||
337 | __in_z LPCWSTR wzServer, | ||
338 | __in_z LPCWSTR wzInstance, | ||
339 | __in_z LPCWSTR wzDatabase, | ||
340 | __in BOOL fIntegratedAuth, | ||
341 | __in_z LPCWSTR wzUser, | ||
342 | __in_z LPCWSTR wzPassword, | ||
343 | __in_opt const SQL_FILESPEC* psfDatabase, | ||
344 | __in_opt const SQL_FILESPEC* psfLog, | ||
345 | __out_opt BSTR* pbstrErrorDescription | ||
346 | ) | ||
347 | { | ||
348 | Assert(wzServer && wzDatabase && *wzDatabase); | ||
349 | |||
350 | HRESULT hr = S_OK; | ||
351 | IDBCreateSession* pidbSession = NULL; | ||
352 | |||
353 | // | ||
354 | // connect to the master database to create the new database | ||
355 | // | ||
356 | hr = SqlConnectDatabase(wzServer, wzInstance, L"master", fIntegratedAuth, wzUser, wzPassword, &pidbSession); | ||
357 | SqlExitOnFailure(hr, "failed to connect to 'master' database on server %ls", wzServer); | ||
358 | |||
359 | hr = SqlSessionDatabaseEnsureExists(pidbSession, wzDatabase, psfDatabase, psfLog, pbstrErrorDescription); | ||
360 | SqlExitOnFailure(hr, "failed to create database: %ls", wzDatabase); | ||
361 | |||
362 | Assert(S_OK == hr); | ||
363 | LExit: | ||
364 | ReleaseObject(pidbSession); | ||
365 | |||
366 | return hr; | ||
367 | } | ||
368 | |||
369 | |||
370 | /******************************************************************** | ||
371 | SqlSessionDatabaseEnsureExists - creates a database if it does not exist | ||
372 | |||
373 | NOTE: pidbSession must be connected to the master database | ||
374 | ********************************************************************/ | ||
375 | extern "C" HRESULT DAPI SqlSessionDatabaseEnsureExists( | ||
376 | __in IDBCreateSession* pidbSession, | ||
377 | __in_z LPCWSTR wzDatabase, | ||
378 | __in_opt const SQL_FILESPEC* psfDatabase, | ||
379 | __in_opt const SQL_FILESPEC* psfLog, | ||
380 | __out_opt BSTR* pbstrErrorDescription | ||
381 | ) | ||
382 | { | ||
383 | Assert(pidbSession && wzDatabase && *wzDatabase); | ||
384 | |||
385 | HRESULT hr = S_OK; | ||
386 | |||
387 | hr = SqlSessionDatabaseExists(pidbSession, wzDatabase, pbstrErrorDescription); | ||
388 | SqlExitOnFailure(hr, "failed to determine if exists, database: %ls", wzDatabase); | ||
389 | |||
390 | if (S_FALSE == hr) | ||
391 | { | ||
392 | hr = SqlSessionCreateDatabase(pidbSession, wzDatabase, psfDatabase, psfLog, pbstrErrorDescription); | ||
393 | SqlExitOnFailure(hr, "failed to create database: %ls", wzDatabase); | ||
394 | } | ||
395 | // else database already exists, return S_FALSE | ||
396 | |||
397 | Assert(S_OK == hr); | ||
398 | LExit: | ||
399 | |||
400 | return hr; | ||
401 | } | ||
402 | |||
403 | |||
404 | /******************************************************************** | ||
405 | SqlCreateDatabase - creates a database on the server | ||
406 | |||
407 | NOTE: wzInstance is optional | ||
408 | if fIntegratedAuth is set then wzUser and wzPassword are ignored | ||
409 | ********************************************************************/ | ||
410 | extern "C" HRESULT DAPI SqlCreateDatabase( | ||
411 | __in_z LPCWSTR wzServer, | ||
412 | __in_z LPCWSTR wzInstance, | ||
413 | __in_z LPCWSTR wzDatabase, | ||
414 | __in BOOL fIntegratedAuth, | ||
415 | __in_z LPCWSTR wzUser, | ||
416 | __in_z LPCWSTR wzPassword, | ||
417 | __in_opt const SQL_FILESPEC* psfDatabase, | ||
418 | __in_opt const SQL_FILESPEC* psfLog, | ||
419 | __out_opt BSTR* pbstrErrorDescription | ||
420 | ) | ||
421 | { | ||
422 | Assert(wzServer && wzDatabase && *wzDatabase); | ||
423 | |||
424 | HRESULT hr = S_OK; | ||
425 | IDBCreateSession* pidbSession = NULL; | ||
426 | |||
427 | // | ||
428 | // connect to the master database to create the new database | ||
429 | // | ||
430 | hr = SqlConnectDatabase(wzServer, wzInstance, L"master", fIntegratedAuth, wzUser, wzPassword, &pidbSession); | ||
431 | SqlExitOnFailure(hr, "failed to connect to 'master' database on server %ls", wzServer); | ||
432 | |||
433 | hr = SqlSessionCreateDatabase(pidbSession, wzDatabase, psfDatabase, psfLog, pbstrErrorDescription); | ||
434 | SqlExitOnFailure(hr, "failed to create database: %ls", wzDatabase); | ||
435 | |||
436 | Assert(S_OK == hr); | ||
437 | LExit: | ||
438 | ReleaseObject(pidbSession); | ||
439 | |||
440 | return hr; | ||
441 | } | ||
442 | |||
443 | |||
444 | /******************************************************************** | ||
445 | SqlSessionCreateDatabase - creates a database on the server | ||
446 | |||
447 | NOTE: pidbSession must be connected to the master database | ||
448 | ********************************************************************/ | ||
449 | extern "C" HRESULT DAPI SqlSessionCreateDatabase( | ||
450 | __in IDBCreateSession* pidbSession, | ||
451 | __in_z LPCWSTR wzDatabase, | ||
452 | __in_opt const SQL_FILESPEC* psfDatabase, | ||
453 | __in_opt const SQL_FILESPEC* psfLog, | ||
454 | __out_opt BSTR* pbstrErrorDescription | ||
455 | ) | ||
456 | { | ||
457 | HRESULT hr = S_OK; | ||
458 | LPWSTR pwzDbFile = NULL; | ||
459 | LPWSTR pwzLogFile = NULL; | ||
460 | LPWSTR pwzQuery = NULL; | ||
461 | LPWSTR pwzDatabaseEscaped = NULL; | ||
462 | |||
463 | if (psfDatabase) | ||
464 | { | ||
465 | hr = FileSpecToString(psfDatabase, &pwzDbFile); | ||
466 | SqlExitOnFailure(hr, "failed to convert db filespec to string"); | ||
467 | } | ||
468 | |||
469 | if (psfLog) | ||
470 | { | ||
471 | hr = FileSpecToString(psfLog, &pwzLogFile); | ||
472 | SqlExitOnFailure(hr, "failed to convert log filespec to string"); | ||
473 | } | ||
474 | |||
475 | hr = EscapeSqlIdentifier(wzDatabase, &pwzDatabaseEscaped); | ||
476 | SqlExitOnFailure(hr, "failed to escape database string"); | ||
477 | |||
478 | hr = StrAllocFormatted(&pwzQuery, L"CREATE DATABASE %s %s%s %s%s", pwzDatabaseEscaped, pwzDbFile ? L"ON " : L"", pwzDbFile ? pwzDbFile : L"", pwzLogFile ? L"LOG ON " : L"", pwzLogFile ? pwzLogFile : L""); | ||
479 | SqlExitOnFailure(hr, "failed to allocate query to create database: %ls", pwzDatabaseEscaped); | ||
480 | |||
481 | hr = SqlSessionExecuteQuery(pidbSession, pwzQuery, NULL, NULL, pbstrErrorDescription); | ||
482 | SqlExitOnFailure(hr, "failed to create database: %ls, Query: %ls", pwzDatabaseEscaped, pwzQuery); | ||
483 | |||
484 | LExit: | ||
485 | ReleaseStr(pwzQuery); | ||
486 | ReleaseStr(pwzLogFile); | ||
487 | ReleaseStr(pwzDbFile); | ||
488 | ReleaseStr(pwzDatabaseEscaped); | ||
489 | |||
490 | return hr; | ||
491 | } | ||
492 | |||
493 | |||
494 | /******************************************************************** | ||
495 | SqlDropDatabase - removes a database from a server if it exists | ||
496 | |||
497 | NOTE: wzInstance is optional | ||
498 | if fIntegratedAuth is set then wzUser and wzPassword are ignored | ||
499 | ********************************************************************/ | ||
500 | extern "C" HRESULT DAPI SqlDropDatabase( | ||
501 | __in_z LPCWSTR wzServer, | ||
502 | __in_z LPCWSTR wzInstance, | ||
503 | __in_z LPCWSTR wzDatabase, | ||
504 | __in BOOL fIntegratedAuth, | ||
505 | __in_z LPCWSTR wzUser, | ||
506 | __in_z LPCWSTR wzPassword, | ||
507 | __out_opt BSTR* pbstrErrorDescription | ||
508 | ) | ||
509 | { | ||
510 | Assert(wzServer && wzDatabase && *wzDatabase); | ||
511 | |||
512 | HRESULT hr = S_OK; | ||
513 | IDBCreateSession* pidbSession = NULL; | ||
514 | |||
515 | // | ||
516 | // connect to the master database to search for wzDatabase | ||
517 | // | ||
518 | hr = SqlConnectDatabase(wzServer, wzInstance, L"master", fIntegratedAuth, wzUser, wzPassword, &pidbSession); | ||
519 | SqlExitOnFailure(hr, "Failed to connect to 'master' database"); | ||
520 | |||
521 | hr = SqlSessionDropDatabase(pidbSession, wzDatabase, pbstrErrorDescription); | ||
522 | |||
523 | LExit: | ||
524 | ReleaseObject(pidbSession); | ||
525 | |||
526 | return hr; | ||
527 | } | ||
528 | |||
529 | |||
530 | /******************************************************************** | ||
531 | SqlSessionDropDatabase - removes a database from a server if it exists | ||
532 | |||
533 | NOTE: pidbSession must be connected to the master database | ||
534 | ********************************************************************/ | ||
535 | extern "C" HRESULT DAPI SqlSessionDropDatabase( | ||
536 | __in IDBCreateSession* pidbSession, | ||
537 | __in_z LPCWSTR wzDatabase, | ||
538 | __out_opt BSTR* pbstrErrorDescription | ||
539 | ) | ||
540 | { | ||
541 | Assert(pidbSession && wzDatabase && *wzDatabase); | ||
542 | |||
543 | HRESULT hr = S_OK; | ||
544 | LPWSTR pwzQuery = NULL; | ||
545 | LPWSTR pwzDatabaseEscaped = NULL; | ||
546 | |||
547 | hr = SqlSessionDatabaseExists(pidbSession, wzDatabase, pbstrErrorDescription); | ||
548 | SqlExitOnFailure(hr, "failed to determine if exists, database: %ls", wzDatabase); | ||
549 | |||
550 | hr = EscapeSqlIdentifier(wzDatabase, &pwzDatabaseEscaped); | ||
551 | SqlExitOnFailure(hr, "failed to escape database string"); | ||
552 | |||
553 | if (S_OK == hr) | ||
554 | { | ||
555 | hr = StrAllocFormatted(&pwzQuery, L"DROP DATABASE %s", pwzDatabaseEscaped); | ||
556 | SqlExitOnFailure(hr, "failed to allocate query to drop database: %ls", pwzDatabaseEscaped); | ||
557 | |||
558 | hr = SqlSessionExecuteQuery(pidbSession, pwzQuery, NULL, NULL, pbstrErrorDescription); | ||
559 | SqlExitOnFailure(hr, "Failed to drop database"); | ||
560 | } | ||
561 | |||
562 | LExit: | ||
563 | ReleaseStr(pwzQuery); | ||
564 | ReleaseStr(pwzDatabaseEscaped); | ||
565 | |||
566 | return hr; | ||
567 | } | ||
568 | |||
569 | |||
570 | /******************************************************************** | ||
571 | SqlSessionExecuteQuery - executes a query and returns the results if desired | ||
572 | |||
573 | NOTE: ppirs and pcRoes and pbstrErrorDescription are optional | ||
574 | ********************************************************************/ | ||
575 | extern "C" HRESULT DAPI SqlSessionExecuteQuery( | ||
576 | __in IDBCreateSession* pidbSession, | ||
577 | __in __sql_command LPCWSTR wzSql, | ||
578 | __out_opt IRowset** ppirs, | ||
579 | __out_opt DBROWCOUNT* pcRows, | ||
580 | __out_opt BSTR* pbstrErrorDescription | ||
581 | ) | ||
582 | { | ||
583 | Assert(pidbSession); | ||
584 | |||
585 | HRESULT hr = S_OK; | ||
586 | IDBCreateCommand* pidbCommand = NULL; | ||
587 | ICommandText* picmdText = NULL; | ||
588 | ICommand* picmd = NULL; | ||
589 | DBROWCOUNT cRows = 0; | ||
590 | |||
591 | if (pcRows) | ||
592 | { | ||
593 | *pcRows = NULL; | ||
594 | } | ||
595 | |||
596 | // | ||
597 | // create the command | ||
598 | // | ||
599 | hr = pidbSession->CreateSession(NULL, IID_IDBCreateCommand, (IUnknown**)&pidbCommand); | ||
600 | SqlExitOnFailure(hr, "failed to create database session"); | ||
601 | hr = pidbCommand->CreateCommand(NULL, IID_ICommand, (IUnknown**)&picmd); | ||
602 | SqlExitOnFailure(hr, "failed to create command to execute session"); | ||
603 | |||
604 | // | ||
605 | // set the sql text into the command | ||
606 | // | ||
607 | hr = picmd->QueryInterface(IID_ICommandText, (LPVOID*)&picmdText); | ||
608 | SqlExitOnFailure(hr, "failed to get command text object for command"); | ||
609 | hr = picmdText->SetCommandText(DBGUID_DEFAULT , wzSql); | ||
610 | SqlExitOnFailure(hr, "failed to set SQL string: %ls", wzSql); | ||
611 | |||
612 | // | ||
613 | // execute the command | ||
614 | // | ||
615 | hr = picmd->Execute(NULL, (ppirs) ? IID_IRowset : IID_NULL, NULL, &cRows, reinterpret_cast<IUnknown**>(ppirs)); | ||
616 | SqlExitOnFailure(hr, "failed to execute SQL string: %ls", wzSql); | ||
617 | |||
618 | if (DB_S_ERRORSOCCURRED == hr) | ||
619 | { | ||
620 | hr = E_FAIL; | ||
621 | } | ||
622 | |||
623 | if (pcRows) | ||
624 | { | ||
625 | *pcRows = cRows; | ||
626 | } | ||
627 | |||
628 | LExit: | ||
629 | |||
630 | if (FAILED(hr) && picmd && pbstrErrorDescription) | ||
631 | { | ||
632 | HRESULT hrGetErrors = SqlGetErrorInfo(picmd, IID_ICommandText, 0x409, NULL, pbstrErrorDescription); // TODO: use current locale instead of always American-English | ||
633 | if (FAILED(hrGetErrors)) | ||
634 | { | ||
635 | ReleaseBSTR(*pbstrErrorDescription); | ||
636 | } | ||
637 | } | ||
638 | |||
639 | ReleaseObject(picmd); | ||
640 | ReleaseObject(picmdText); | ||
641 | ReleaseObject(pidbCommand); | ||
642 | |||
643 | return hr; | ||
644 | } | ||
645 | |||
646 | |||
647 | /******************************************************************** | ||
648 | SqlCommandExecuteQuery - executes a SQL command and returns the results if desired | ||
649 | |||
650 | NOTE: ppirs and pcRoes are optional | ||
651 | ********************************************************************/ | ||
652 | extern "C" HRESULT DAPI SqlCommandExecuteQuery( | ||
653 | __in IDBCreateCommand* pidbCommand, | ||
654 | __in __sql_command LPCWSTR wzSql, | ||
655 | __out IRowset** ppirs, | ||
656 | __out DBROWCOUNT* pcRows | ||
657 | ) | ||
658 | { | ||
659 | Assert(pidbCommand); | ||
660 | |||
661 | HRESULT hr = S_OK; | ||
662 | ICommandText* picmdText = NULL; | ||
663 | ICommand* picmd = NULL; | ||
664 | DBROWCOUNT cRows = 0; | ||
665 | |||
666 | if (pcRows) | ||
667 | { | ||
668 | *pcRows = NULL; | ||
669 | } | ||
670 | |||
671 | // | ||
672 | // create the command | ||
673 | // | ||
674 | hr = pidbCommand->CreateCommand(NULL, IID_ICommand, (IUnknown**)&picmd); | ||
675 | SqlExitOnFailure(hr, "failed to create command to execute session"); | ||
676 | |||
677 | // | ||
678 | // set the sql text into the command | ||
679 | // | ||
680 | hr = picmd->QueryInterface(IID_ICommandText, (LPVOID*)&picmdText); | ||
681 | SqlExitOnFailure(hr, "failed to get command text object for command"); | ||
682 | hr = picmdText->SetCommandText(DBGUID_DEFAULT , wzSql); | ||
683 | SqlExitOnFailure(hr, "failed to set SQL string: %ls", wzSql); | ||
684 | |||
685 | // | ||
686 | // execute the command | ||
687 | // | ||
688 | hr = picmd->Execute(NULL, (ppirs) ? IID_IRowset : IID_NULL, NULL, &cRows, reinterpret_cast<IUnknown**>(ppirs)); | ||
689 | SqlExitOnFailure(hr, "failed to execute SQL string: %ls", wzSql); | ||
690 | |||
691 | if (DB_S_ERRORSOCCURRED == hr) | ||
692 | { | ||
693 | hr = E_FAIL; | ||
694 | } | ||
695 | |||
696 | if (pcRows) | ||
697 | { | ||
698 | *pcRows = cRows; | ||
699 | } | ||
700 | |||
701 | LExit: | ||
702 | ReleaseObject(picmd); | ||
703 | ReleaseObject(picmdText); | ||
704 | |||
705 | return hr; | ||
706 | } | ||
707 | |||
708 | |||
709 | /******************************************************************** | ||
710 | SqlGetErrorInfo - gets error information from the last SQL function call | ||
711 | |||
712 | NOTE: pbstrErrorSource and pbstrErrorDescription are optional | ||
713 | ********************************************************************/ | ||
714 | extern "C" HRESULT DAPI SqlGetErrorInfo( | ||
715 | __in IUnknown* pObjectWithError, | ||
716 | __in REFIID IID_InterfaceWithError, | ||
717 | __in DWORD dwLocaleId, | ||
718 | __out_opt BSTR* pbstrErrorSource, | ||
719 | __out_opt BSTR* pbstrErrorDescription | ||
720 | ) | ||
721 | { | ||
722 | HRESULT hr = S_OK; | ||
723 | Assert(pObjectWithError); | ||
724 | |||
725 | // interfaces needed to extract error information out | ||
726 | ISupportErrorInfo* pISupportErrorInfo = NULL; | ||
727 | IErrorInfo* pIErrorInfoAll = NULL; | ||
728 | IErrorRecords* pIErrorRecords = NULL; | ||
729 | IErrorInfo* pIErrorInfoRecord = NULL; | ||
730 | |||
731 | // only ask for error information if the interface supports it. | ||
732 | hr = pObjectWithError->QueryInterface(IID_ISupportErrorInfo,(void**)&pISupportErrorInfo); | ||
733 | SqlExitOnFailure(hr, "No error information was found for object."); | ||
734 | |||
735 | hr = pISupportErrorInfo->InterfaceSupportsErrorInfo(IID_InterfaceWithError); | ||
736 | SqlExitOnFailure(hr, "InterfaceWithError is not supported for object with error"); | ||
737 | |||
738 | // ignore the return of GetErrorInfo it can succeed and return a NULL pointer in pIErrorInfoAll anyway | ||
739 | hr = ::GetErrorInfo(0, &pIErrorInfoAll); | ||
740 | SqlExitOnFailure(hr, "failed to get error info"); | ||
741 | |||
742 | if (S_OK == hr && pIErrorInfoAll) | ||
743 | { | ||
744 | // see if it's a valid OLE DB IErrorInfo interface that exposes a list of records | ||
745 | hr = pIErrorInfoAll->QueryInterface(IID_IErrorRecords, (void**)&pIErrorRecords); | ||
746 | if (SUCCEEDED(hr)) | ||
747 | { | ||
748 | ULONG cErrors = 0; | ||
749 | pIErrorRecords->GetRecordCount(&cErrors); | ||
750 | |||
751 | // get the error information for each record | ||
752 | for (ULONG i = 0; i < cErrors; ++i) | ||
753 | { | ||
754 | hr = pIErrorRecords->GetErrorInfo(i, dwLocaleId, &pIErrorInfoRecord); | ||
755 | if (SUCCEEDED(hr)) | ||
756 | { | ||
757 | if (pbstrErrorSource) | ||
758 | { | ||
759 | pIErrorInfoRecord->GetSource(pbstrErrorSource); | ||
760 | } | ||
761 | if (pbstrErrorDescription) | ||
762 | { | ||
763 | pIErrorInfoRecord->GetDescription(pbstrErrorDescription); | ||
764 | } | ||
765 | |||
766 | ReleaseNullObject(pIErrorInfoRecord); | ||
767 | |||
768 | break; // TODO: return more than one error in the future! | ||
769 | } | ||
770 | } | ||
771 | |||
772 | ReleaseNullObject(pIErrorRecords); | ||
773 | } | ||
774 | else // we have a simple error record | ||
775 | { | ||
776 | if (pbstrErrorSource) | ||
777 | { | ||
778 | pIErrorInfoAll->GetSource(pbstrErrorSource); | ||
779 | } | ||
780 | if (pbstrErrorDescription) | ||
781 | { | ||
782 | pIErrorInfoAll->GetDescription(pbstrErrorDescription); | ||
783 | } | ||
784 | } | ||
785 | } | ||
786 | else | ||
787 | { | ||
788 | hr = E_NOMOREITEMS; | ||
789 | } | ||
790 | |||
791 | LExit: | ||
792 | ReleaseObject(pIErrorInfoRecord); | ||
793 | ReleaseObject(pIErrorRecords); | ||
794 | ReleaseObject(pIErrorInfoAll); | ||
795 | ReleaseObject(pISupportErrorInfo); | ||
796 | |||
797 | return hr; | ||
798 | } | ||
799 | |||
800 | |||
801 | // | ||
802 | // private | ||
803 | // | ||
804 | |||
805 | static HRESULT InitializeDatabaseConnection( | ||
806 | __in REFCLSID rclsid, | ||
807 | __in_z LPCSTR szFriendlyClsidName, | ||
808 | __in DBPROPSET rgdbpsetInit[], | ||
809 | __in_ecount(rgdbpsetInit) DWORD cdbpsetInit, | ||
810 | __out IDBCreateSession** ppidbSession | ||
811 | ) | ||
812 | { | ||
813 | Unused(szFriendlyClsidName); // only used in DEBUG builds | ||
814 | |||
815 | HRESULT hr = S_OK; | ||
816 | IDBInitialize* pidbInitialize = NULL; | ||
817 | IDBProperties* pidbProperties = NULL; | ||
818 | |||
819 | hr = ::CoCreateInstance(rclsid, NULL, CLSCTX_INPROC_SERVER, IID_IDBInitialize, (LPVOID*)&pidbInitialize); | ||
820 | SqlExitOnFailure(hr, "failed to initialize %s", szFriendlyClsidName); | ||
821 | |||
822 | // create and set the property set | ||
823 | hr = pidbInitialize->QueryInterface(IID_IDBProperties, (LPVOID*)&pidbProperties); | ||
824 | SqlExitOnFailure(hr, "failed to get IID_IDBProperties for %s", szFriendlyClsidName); | ||
825 | |||
826 | hr = pidbProperties->SetProperties(cdbpsetInit, rgdbpsetInit); | ||
827 | SqlExitOnFailure(hr, "failed to set properties for %s", szFriendlyClsidName); | ||
828 | |||
829 | // initialize connection to datasource | ||
830 | hr = pidbInitialize->Initialize(); | ||
831 | if (FAILED(hr)) | ||
832 | { | ||
833 | DumpErrorRecords(); | ||
834 | } | ||
835 | SqlExitOnFailure(hr, "failed to initialize connection for %s", szFriendlyClsidName); | ||
836 | |||
837 | hr = pidbInitialize->QueryInterface(IID_IDBCreateSession, (LPVOID*)ppidbSession); | ||
838 | SqlExitOnFailure(hr, "failed to query for connection session for %s", szFriendlyClsidName); | ||
839 | |||
840 | LExit: | ||
841 | ReleaseObject(pidbProperties); | ||
842 | ReleaseObject(pidbInitialize); | ||
843 | |||
844 | return hr; | ||
845 | } | ||
846 | |||
847 | HRESULT DumpErrorRecords() | ||
848 | { | ||
849 | HRESULT hr = S_OK; | ||
850 | IErrorInfo* pIErrorInfo = NULL; | ||
851 | IErrorRecords* pIErrorRecords = NULL; | ||
852 | IErrorInfo* pIErrorInfoRecord = NULL; | ||
853 | BSTR bstrDescription = NULL; | ||
854 | ULONG i = 0; | ||
855 | ULONG cRecords = 0; | ||
856 | ERRORINFO ErrorInfo = { }; | ||
857 | |||
858 | // Get IErrorInfo pointer from OLE. | ||
859 | hr = ::GetErrorInfo(0, &pIErrorInfo); | ||
860 | if (FAILED(hr)) | ||
861 | { | ||
862 | ExitFunction(); | ||
863 | } | ||
864 | |||
865 | // QI for IID_IErrorRecords. | ||
866 | hr = pIErrorInfo->QueryInterface(IID_IErrorRecords, (void**)&pIErrorRecords); | ||
867 | if (FAILED(hr)) | ||
868 | { | ||
869 | ExitFunction(); | ||
870 | } | ||
871 | |||
872 | // Get error record count. | ||
873 | hr = pIErrorRecords->GetRecordCount(&cRecords); | ||
874 | if (FAILED(hr)) | ||
875 | { | ||
876 | ExitFunction(); | ||
877 | } | ||
878 | |||
879 | // Loop through the error records. | ||
880 | for (i = 0; i < cRecords; i++) | ||
881 | { | ||
882 | // Get pIErrorInfo from pIErrorRecords. | ||
883 | hr = pIErrorRecords->GetErrorInfo(i, 1033, &pIErrorInfoRecord); | ||
884 | |||
885 | if (SUCCEEDED(hr)) | ||
886 | { | ||
887 | // Get error description and source. | ||
888 | hr = pIErrorInfoRecord->GetDescription(&bstrDescription); | ||
889 | |||
890 | // Retrieve the ErrorInfo structures. | ||
891 | hr = pIErrorRecords->GetBasicErrorInfo(i, &ErrorInfo); | ||
892 | |||
893 | SqlExitTrace(ErrorInfo.hrError, "SQL error %lu/%lu: %ls", i + 1, cRecords, bstrDescription); | ||
894 | |||
895 | ReleaseNullObject(pIErrorInfoRecord); | ||
896 | ReleaseNullBSTR(bstrDescription); | ||
897 | } | ||
898 | } | ||
899 | |||
900 | LExit: | ||
901 | ReleaseNullBSTR(bstrDescription); | ||
902 | ReleaseObject(pIErrorInfoRecord); | ||
903 | ReleaseObject(pIErrorRecords); | ||
904 | ReleaseObject(pIErrorInfo); | ||
905 | |||
906 | return hr; | ||
907 | } | ||
908 | |||
909 | /******************************************************************** | ||
910 | FileSpecToString | ||
911 | |||
912 | *********************************************************************/ | ||
913 | static HRESULT FileSpecToString( | ||
914 | __in const SQL_FILESPEC* psf, | ||
915 | __out LPWSTR* ppwz | ||
916 | ) | ||
917 | { | ||
918 | Assert(psf && ppwz); | ||
919 | |||
920 | HRESULT hr = S_OK; | ||
921 | LPWSTR pwz = NULL; | ||
922 | |||
923 | hr = StrAllocString(&pwz, L"(", 1024); | ||
924 | SqlExitOnFailure(hr, "failed to allocate string for database file info"); | ||
925 | |||
926 | SqlExitOnNull(*psf->wzName, hr, E_INVALIDARG, "logical name not specified in database file info"); | ||
927 | SqlExitOnNull(*psf->wzFilename, hr, E_INVALIDARG, "filename not specified in database file info"); | ||
928 | |||
929 | hr = StrAllocFormatted(&pwz, L"%sNAME=%s", pwz, psf->wzName); | ||
930 | SqlExitOnFailure(hr, "failed to format database file info name: %ls", psf->wzName); | ||
931 | |||
932 | hr = StrAllocFormatted(&pwz, L"%s, FILENAME='%s'", pwz, psf->wzFilename); | ||
933 | SqlExitOnFailure(hr, "failed to format database file info filename: %ls", psf->wzFilename); | ||
934 | |||
935 | if (0 != psf->wzSize[0]) | ||
936 | { | ||
937 | hr = StrAllocFormatted(&pwz, L"%s, SIZE=%s", pwz, psf->wzSize); | ||
938 | SqlExitOnFailure(hr, "failed to format database file info size: %ls", psf->wzSize); | ||
939 | } | ||
940 | |||
941 | if (0 != psf->wzMaxSize[0]) | ||
942 | { | ||
943 | hr = StrAllocFormatted(&pwz, L"%s, MAXSIZE=%s", pwz, psf->wzMaxSize); | ||
944 | SqlExitOnFailure(hr, "failed to format database file info maxsize: %ls", psf->wzMaxSize); | ||
945 | } | ||
946 | |||
947 | if (0 != psf->wzGrow[0]) | ||
948 | { | ||
949 | hr = StrAllocFormatted(&pwz, L"%s, FILEGROWTH=%s", pwz, psf->wzGrow); | ||
950 | SqlExitOnFailure(hr, "failed to format database file info growth: %ls", psf->wzGrow); | ||
951 | } | ||
952 | |||
953 | hr = StrAllocFormatted(&pwz, L"%s)", pwz); | ||
954 | SqlExitOnFailure(hr, "failed to allocate string for file spec"); | ||
955 | |||
956 | *ppwz = pwz; | ||
957 | pwz = NULL; // null here so it doesn't get freed below | ||
958 | |||
959 | LExit: | ||
960 | ReleaseStr(pwz); | ||
961 | return hr; | ||
962 | } | ||
963 | |||
964 | static HRESULT EscapeSqlIdentifier( | ||
965 | __in_z LPCWSTR wzIdentifier, | ||
966 | __deref_out_z LPWSTR* ppwz | ||
967 | ) | ||
968 | { | ||
969 | Assert(ppwz); | ||
970 | |||
971 | HRESULT hr = S_OK; | ||
972 | LPWSTR pwz = NULL; | ||
973 | |||
974 | if (wzIdentifier == NULL) | ||
975 | { | ||
976 | //Just ignore a NULL identifier and clear out the result | ||
977 | ReleaseNullStr(*ppwz); | ||
978 | ExitFunction(); | ||
979 | } | ||
980 | |||
981 | int cchIdentifier = lstrlenW(wzIdentifier); | ||
982 | |||
983 | //If an empty string or already escaped just copy | ||
984 | if (cchIdentifier == 0 || (wzIdentifier[0] == '[' && wzIdentifier[cchIdentifier-1] == ']')) | ||
985 | { | ||
986 | hr = StrAllocString(&pwz, wzIdentifier, 0); | ||
987 | SqlExitOnFailure(hr, "failed to format database name: %ls", wzIdentifier); | ||
988 | } | ||
989 | else | ||
990 | { | ||
991 | //escape it | ||
992 | hr = StrAllocFormatted(&pwz, L"[%s]", wzIdentifier); | ||
993 | SqlExitOnFailure(hr, "failed to format escaped database name: %ls", wzIdentifier); | ||
994 | } | ||
995 | |||
996 | *ppwz = pwz; | ||
997 | pwz = NULL; // null here so it doesn't get freed below | ||
998 | |||
999 | LExit: | ||
1000 | ReleaseStr(pwz); | ||
1001 | return hr; | ||
1002 | } | ||