Line data Source code
1 : /*
2 : * SPDX-License-Identifier: MPL-2.0
3 : *
4 : * This Source Code Form is subject to the terms of the Mozilla Public
5 : * License, v. 2.0. If a copy of the MPL was not distributed with this
6 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
7 : *
8 : * Copyright 2024 MonetDB Foundation;
9 : * Copyright August 2008 - 2023 MonetDB B.V.;
10 : * Copyright 1997 - July 2008 CWI.
11 : */
12 :
13 : /*
14 : * This code was created by Peter Harvey (mostly during Christmas 98/99).
15 : * This code is LGPL. Please ensure that this message remains in future
16 : * distributions and uses of this code (thats about all I get out of it).
17 : * - Peter Harvey pharvey@codebydesign.com
18 : *
19 : * This file has been modified for the MonetDB project. See the file
20 : * Copyright in this directory for more information.
21 : */
22 :
23 : /**********************************************************************
24 : * SQLDriverConnect()
25 : * CLI Compliance: ODBC (Microsoft)
26 : *
27 : * Author: Martin van Dinther, Sjoerd Mullender
28 : * Date : 30 aug 2002
29 : *
30 : **********************************************************************/
31 :
32 : #include "ODBCGlobal.h"
33 : #include "ODBCDbc.h"
34 : #include "ODBCUtil.h"
35 : #ifdef HAVE_STRINGS_H
36 : #include <strings.h> /* for strcasecmp */
37 : #else
38 : #include <string.h>
39 : #endif
40 :
41 : int
42 4 : ODBCGetKeyAttr(const SQLCHAR **conn, SQLSMALLINT *nconn, char **key, char **attr)
43 : {
44 4 : const SQLCHAR *p;
45 4 : size_t len;
46 :
47 4 : *key = *attr = NULL;
48 :
49 4 : p = *conn;
50 4 : if (!**conn)
51 : return 0;
52 8 : while (*nconn > 0 && **conn && **conn != '=' && **conn != ';') {
53 6 : (*conn)++;
54 6 : (*nconn)--;
55 : }
56 2 : if (*nconn == 0 || !**conn || **conn == ';')
57 : return 0;
58 2 : len = *conn - p;
59 2 : *key = (char *) malloc(len + 1);
60 2 : if (*key == NULL)
61 : return -1;
62 2 : strcpy_len(*key, (char *) p, len + 1);
63 2 : (*conn)++;
64 2 : (*nconn)--;
65 2 : p = *conn;
66 :
67 2 : if (*nconn > 0 && **conn == '{' && strcasecmp(*key, "DRIVER") == 0) {
68 0 : (*conn)++;
69 0 : (*nconn)--;
70 0 : p++;
71 0 : while (*nconn > 0 && **conn && **conn != '}') {
72 0 : (*conn)++;
73 0 : (*nconn)--;
74 : }
75 0 : len = *conn - p;
76 0 : *attr = (char *) malloc(len + 1);
77 0 : if (*attr == NULL) {
78 0 : free(*key);
79 0 : *key = NULL;
80 0 : return -1;
81 : }
82 0 : strcpy_len(*attr, (char *) p, len + 1);
83 0 : (*conn)++;
84 0 : (*nconn)--;
85 : /* should check that *nconn == 0 || **conn == ';' */
86 : } else {
87 26 : while (*nconn > 0 && **conn && **conn != ';') {
88 24 : (*conn)++;
89 24 : (*nconn)--;
90 : }
91 2 : len = *conn - p;
92 2 : *attr = (char *) malloc(len + 1);
93 2 : if (*attr == NULL) {
94 0 : free(*key);
95 0 : *key = NULL;
96 0 : return -1;
97 : }
98 2 : strcpy_len(*attr, (char *) p, len + 1);
99 : }
100 2 : if (*nconn > 0 && **conn) {
101 0 : (*conn)++;
102 0 : (*nconn)--;
103 : }
104 : return 1;
105 : }
106 :
107 : SQLRETURN
108 2 : ODBCConnectionString(SQLRETURN rc,
109 : ODBCDbc *dbc,
110 : SQLCHAR *OutConnectionString,
111 : SQLSMALLINT BufferLength,
112 : SQLSMALLINT *StringLength2Ptr,
113 : const char *dsn,
114 : const char *uid,
115 : const char *pwd,
116 : const char *host,
117 : int port,
118 : const char *database,
119 : int mapToLongVarchar)
120 : {
121 2 : int n;
122 : #ifdef ODBCDEBUG
123 2 : SQLCHAR *buf = OutConnectionString;
124 2 : int buflen = BufferLength;
125 : #endif
126 :
127 2 : if (OutConnectionString == NULL)
128 : BufferLength = -1;
129 1 : if (BufferLength > 0) {
130 1 : n = snprintf((char *) OutConnectionString, BufferLength,
131 : "DSN=%s;", dsn ? dsn : "DEFAULT");
132 : /* some snprintf's return -1 if buffer too small */
133 1 : if (n < 0)
134 0 : n = BufferLength + 1; /* make sure it becomes < 0 */
135 1 : BufferLength -= n;
136 1 : OutConnectionString += n;
137 : } else {
138 : BufferLength = -1;
139 : }
140 2 : if (uid) {
141 0 : if (BufferLength > 0) {
142 0 : n = snprintf((char *) OutConnectionString,
143 : BufferLength, "UID=%s;", uid);
144 0 : if (n < 0)
145 0 : n = BufferLength + 1;
146 0 : BufferLength -= n;
147 0 : OutConnectionString += n;
148 : } else {
149 : BufferLength = -1;
150 : }
151 : }
152 2 : if (pwd) {
153 0 : if (BufferLength > 0) {
154 0 : n = snprintf((char *) OutConnectionString,
155 : BufferLength, "PWD=%s;", pwd);
156 0 : if (n < 0)
157 0 : n = BufferLength + 1;
158 0 : BufferLength -= n;
159 0 : OutConnectionString += n;
160 : } else {
161 : BufferLength = -1;
162 : }
163 : }
164 2 : if (host) {
165 0 : if (BufferLength > 0) {
166 0 : n = snprintf((char *) OutConnectionString,
167 : BufferLength, "HOST=%s;", host);
168 0 : if (n < 0)
169 0 : n = BufferLength + 1;
170 0 : BufferLength -= n;
171 0 : OutConnectionString += n;
172 : } else {
173 : BufferLength = -1;
174 : }
175 : }
176 2 : if (port) {
177 0 : char portbuf[10];
178 :
179 0 : if (BufferLength > 0) {
180 0 : n = snprintf((char *) OutConnectionString,
181 : BufferLength, "PORT=%d;", port);
182 0 : if (n < 0)
183 0 : n = BufferLength + 1;
184 0 : BufferLength -= n;
185 0 : OutConnectionString += n;
186 : } else {
187 : BufferLength = -1;
188 : }
189 0 : port = snprintf(portbuf, sizeof(portbuf), "%d", port);
190 : }
191 2 : if (database) {
192 0 : if (BufferLength > 0) {
193 0 : n = snprintf((char *) OutConnectionString,
194 : BufferLength, "DATABASE=%s;", database);
195 0 : if (n < 0)
196 0 : n = BufferLength + 1;
197 0 : BufferLength -= n;
198 0 : OutConnectionString += n;
199 : } else {
200 : BufferLength = -1;
201 : }
202 : }
203 2 : if (mapToLongVarchar > 0) {
204 0 : if (BufferLength > 0) {
205 0 : n = snprintf((char *) OutConnectionString,
206 : BufferLength, "mapToLongVarchar=%d;", mapToLongVarchar);
207 0 : if (n < 0)
208 0 : n = BufferLength + 1;
209 0 : BufferLength -= n;
210 0 : OutConnectionString += n;
211 : } else {
212 : BufferLength = -1;
213 : }
214 : }
215 2 : n = 0;
216 : #ifdef ODBCDEBUG
217 : #ifdef NATIVE_WIN32
218 : if (ODBCdebug && _wgetenv(L"ODBCDEBUG") == NULL) {
219 : if (BufferLength > 0) {
220 : n = snprintf((char *) OutConnectionString,
221 : BufferLength,
222 : "LOGFILE=%ls;", ODBCdebug);
223 : if (n < 0) {
224 : n = 0;
225 : BufferLength = -1;
226 : } else {
227 : BufferLength -= n;
228 : OutConnectionString += n;
229 : }
230 : } else {
231 : BufferLength = -1;
232 : }
233 : }
234 : #else
235 2 : if (ODBCdebug && getenv("ODBCDEBUG") == NULL) {
236 2 : if (BufferLength > 0) {
237 1 : n = snprintf((char *) OutConnectionString,
238 : BufferLength,
239 : "LOGFILE=%s;", ODBCdebug);
240 1 : if (n < 0) {
241 : n = 0;
242 : BufferLength = -1;
243 : } else {
244 1 : BufferLength -= n;
245 1 : OutConnectionString += n;
246 : }
247 : } else {
248 : BufferLength = -1;
249 : }
250 : }
251 : #endif
252 : #endif
253 :
254 : /* calculate how much space was needed */
255 2 : if (StringLength2Ptr)
256 4 : *StringLength2Ptr = (SQLSMALLINT)
257 2 : (strlen(dsn ? dsn : "DEFAULT") + 5 +
258 2 : (uid ? strlen(uid) + 5 : 0) +
259 2 : (pwd ? strlen(pwd) + 5 : 0) +
260 2 : (host ? strlen(host) + 6 : 0) +
261 2 : (port ? port + 6 : 0) +
262 0 : (database ? strlen(database) + 10 : 0)
263 2 : + n);
264 :
265 : #ifdef ODBCDEBUG
266 2 : ODBCLOG("ConnectionString: \"%.*s\" %d\n", buf ? buflen : 6, buf ? (char *) buf : "(null)", buflen);
267 : #endif
268 :
269 : /* if it didn't fit, say so */
270 2 : if (BufferLength < 0) {
271 : /* String data, right-truncated */
272 2 : addDbcError(dbc, "01004", NULL, 0);
273 2 : return SQL_SUCCESS_WITH_INFO;
274 : }
275 : return rc;
276 : }
277 :
278 : #ifdef ODBCDEBUG
279 : static char *
280 0 : translateDriverCompletion(SQLUSMALLINT DriverCompletion)
281 : {
282 0 : switch (DriverCompletion) {
283 : case SQL_DRIVER_PROMPT:
284 : return "SQL_DRIVER_PROMPT";
285 0 : case SQL_DRIVER_COMPLETE:
286 0 : return "SQL_DRIVER_COMPLETE";
287 0 : case SQL_DRIVER_COMPLETE_REQUIRED:
288 0 : return "SQL_DRIVER_COMPLETE_REQUIRED";
289 0 : case SQL_DRIVER_NOPROMPT:
290 0 : return "SQL_DRIVER_NOPROMPT";
291 0 : default:
292 0 : return "unknown";
293 : }
294 : }
295 : #endif
296 :
297 : static SQLRETURN
298 2 : MNDBDriverConnect(ODBCDbc *dbc,
299 : SQLHWND WindowHandle,
300 : const SQLCHAR *InConnectionString,
301 : SQLSMALLINT StringLength1,
302 : SQLCHAR *OutConnectionString,
303 : SQLSMALLINT BufferLength,
304 : SQLSMALLINT *StringLength2Ptr,
305 : SQLUSMALLINT DriverCompletion,
306 : int tryOnly)
307 : {
308 2 : char *key, *attr;
309 2 : char *dsn = 0, *uid = 0, *pwd = 0, *host = 0, *database = 0;
310 2 : int port = 0, mapToLongVarchar = 0;
311 2 : SQLRETURN rc;
312 2 : int n;
313 :
314 2 : (void) WindowHandle; /* Stefan: unused!? */
315 :
316 : /* check connection state, should not be connected */
317 2 : if (dbc->Connected) {
318 : /* Connection name in use */
319 0 : addDbcError(dbc, "08002", NULL, 0);
320 0 : return SQL_ERROR;
321 : }
322 2 : assert(!dbc->Connected);
323 :
324 2 : fixODBCstring(InConnectionString, StringLength1, SQLSMALLINT,
325 : addDbcError, dbc, return SQL_ERROR);
326 :
327 : #ifdef ODBCDEBUG
328 2 : ODBCLOG("\"%.*s\" %s\n", StringLength1,
329 : (char *) InConnectionString,
330 : translateDriverCompletion(DriverCompletion));
331 : #endif
332 :
333 : /* check input arguments */
334 2 : switch (DriverCompletion) {
335 : case SQL_DRIVER_PROMPT:
336 : case SQL_DRIVER_COMPLETE:
337 : case SQL_DRIVER_COMPLETE_REQUIRED:
338 : case SQL_DRIVER_NOPROMPT:
339 : break;
340 0 : default:
341 : /* Invalid attribute/option identifier */
342 0 : addDbcError(dbc, "HY092", NULL, 0);
343 0 : return SQL_ERROR;
344 : }
345 :
346 4 : while ((n = ODBCGetKeyAttr(&InConnectionString, &StringLength1, &key, &attr)) > 0) {
347 2 : if (strcasecmp(key, "dsn") == 0 && dsn == NULL)
348 2 : dsn = attr;
349 0 : else if (strcasecmp(key, "uid") == 0 && uid == NULL)
350 0 : uid = attr;
351 0 : else if (strcasecmp(key, "pwd") == 0 && pwd == NULL)
352 0 : pwd = attr;
353 0 : else if (strcasecmp(key, "host") == 0 && host == NULL)
354 0 : host = attr;
355 0 : else if (strcasecmp(key, "database") == 0 && database == NULL)
356 0 : database = attr;
357 0 : else if (strcasecmp(key, "port") == 0 && port == 0) {
358 0 : port = atoi(attr);
359 0 : free(attr);
360 0 : } else if (strcasecmp(key, "mapToLongVarchar") == 0 && mapToLongVarchar == 0) {
361 0 : mapToLongVarchar = atoi(attr);
362 0 : free(attr);
363 : #ifdef ODBCDEBUG
364 : #ifdef NATIVE_WIN32
365 : } else if (strcasecmp(key, "logfile") == 0 &&
366 : _wgetenv(L"ODBCDEBUG") == NULL) {
367 : if (ODBCdebug)
368 : free((void *) ODBCdebug); /* discard const */
369 : size_t attrlen = strlen(attr);
370 : SQLWCHAR *wattr = malloc((attrlen + 1) * sizeof(SQLWCHAR));
371 : if (ODBCutf82wchar(attr,
372 : (SQLINTEGER) attrlen,
373 : wattr,
374 : (SQLLEN) ((attrlen + 1) * sizeof(SQLWCHAR)),
375 : NULL,
376 : NULL)) {
377 : free(wattr);
378 : wattr = NULL;
379 : }
380 : free(attr);
381 : ODBCdebug = wattr;
382 : #else
383 0 : } else if (strcasecmp(key, "logfile") == 0 &&
384 0 : getenv("ODBCDEBUG") == NULL) {
385 0 : if (ODBCdebug)
386 0 : free((void *) ODBCdebug); /* discard const */
387 0 : ODBCdebug = attr;
388 : #endif
389 : #endif
390 : } else
391 0 : free(attr);
392 2 : free(key);
393 : }
394 :
395 2 : if (n < 0) {
396 : /* Memory allocation error */
397 0 : addDbcError(dbc, "HY001", NULL, 0);
398 0 : rc = SQL_ERROR;
399 2 : } else if (dsn && strlen(dsn) > SQL_MAX_DSN_LENGTH) {
400 : /* Data source name too long */
401 0 : addDbcError(dbc, "IM010", NULL, 0);
402 0 : rc = SQL_ERROR;
403 2 : } else if (tryOnly) {
404 : rc = SQL_SUCCESS;
405 : } else {
406 1 : rc = MNDBConnect(dbc, (SQLCHAR *) dsn, SQL_NTS,
407 : (SQLCHAR *) uid, SQL_NTS,
408 : (SQLCHAR *) pwd, SQL_NTS,
409 : host, port, database,
410 : mapToLongVarchar);
411 : }
412 :
413 1 : if (SQL_SUCCEEDED(rc)) {
414 2 : rc = ODBCConnectionString(rc, dbc, OutConnectionString,
415 : BufferLength, StringLength2Ptr,
416 : dsn, uid, pwd, host, port, database,
417 : mapToLongVarchar);
418 : }
419 :
420 2 : if (dsn)
421 2 : free(dsn);
422 2 : if (uid)
423 0 : free(uid);
424 2 : if (pwd)
425 0 : free(pwd);
426 2 : if (host)
427 0 : free(host);
428 2 : if (database)
429 0 : free(database);
430 : return rc;
431 : }
432 :
433 : SQLRETURN SQL_API
434 : SQLDriverConnect(SQLHDBC ConnectionHandle,
435 : SQLHWND WindowHandle,
436 : SQLCHAR *InConnectionString,
437 : SQLSMALLINT StringLength1,
438 : SQLCHAR *OutConnectionString,
439 : SQLSMALLINT BufferLength,
440 : SQLSMALLINT *StringLength2Ptr,
441 : SQLUSMALLINT DriverCompletion)
442 : {
443 0 : ODBCDbc *dbc = (ODBCDbc *) ConnectionHandle;
444 :
445 : #ifdef ODBCDEBUG
446 0 : ODBCLOG("SQLDriverConnect %p ", ConnectionHandle);
447 : #endif
448 :
449 0 : if (!isValidDbc(dbc))
450 : return SQL_INVALID_HANDLE;
451 :
452 0 : clearDbcErrors(dbc);
453 :
454 0 : return MNDBDriverConnect(dbc,
455 : WindowHandle,
456 : InConnectionString,
457 : StringLength1,
458 : OutConnectionString,
459 : BufferLength,
460 : StringLength2Ptr,
461 : DriverCompletion,
462 : 0);
463 : }
464 :
465 : SQLRETURN SQL_API
466 : SQLDriverConnectA(SQLHDBC ConnectionHandle,
467 : SQLHWND WindowHandle,
468 : SQLCHAR *InConnectionString,
469 : SQLSMALLINT StringLength1,
470 : SQLCHAR *OutConnectionString,
471 : SQLSMALLINT BufferLength,
472 : SQLSMALLINT *StringLength2Ptr,
473 : SQLUSMALLINT DriverCompletion)
474 : {
475 0 : return SQLDriverConnect(ConnectionHandle,
476 : WindowHandle,
477 : InConnectionString,
478 : StringLength1,
479 : OutConnectionString,
480 : BufferLength,
481 : StringLength2Ptr,
482 : DriverCompletion);
483 : }
484 :
485 : SQLRETURN SQL_API
486 : SQLDriverConnectW(SQLHDBC ConnectionHandle,
487 : SQLHWND WindowHandle,
488 : SQLWCHAR *InConnectionString,
489 : SQLSMALLINT StringLength1,
490 : SQLWCHAR *OutConnectionString,
491 : SQLSMALLINT BufferLength,
492 : SQLSMALLINT *StringLength2Ptr,
493 : SQLUSMALLINT DriverCompletion)
494 : {
495 1 : ODBCDbc *dbc = (ODBCDbc *) ConnectionHandle;
496 1 : SQLCHAR *in = NULL, *out;
497 1 : SQLSMALLINT n;
498 1 : SQLRETURN rc;
499 :
500 : #ifdef ODBCDEBUG
501 1 : ODBCLOG("SQLDriverConnectW %p ", ConnectionHandle);
502 : #endif
503 :
504 1 : if (!isValidDbc(dbc))
505 : return SQL_INVALID_HANDLE;
506 :
507 1 : clearDbcErrors(dbc);
508 :
509 1 : fixWcharIn(InConnectionString, StringLength1, SQLCHAR, in,
510 : addDbcError, dbc, return SQL_ERROR);
511 :
512 1 : rc = MNDBDriverConnect(dbc, WindowHandle, in, SQL_NTS, NULL, 0, &n,
513 : DriverCompletion, 1);
514 1 : if (!SQL_SUCCEEDED(rc))
515 : return rc;
516 1 : clearDbcErrors(dbc);
517 1 : n++; /* account for NUL byte */
518 1 : out = malloc(n);
519 1 : if (out == NULL) {
520 : /* Memory allocation error */
521 0 : addDbcError(dbc, "HY001", NULL, 0);
522 0 : return SQL_ERROR;
523 : }
524 1 : rc = MNDBDriverConnect(dbc, WindowHandle, in, SQL_NTS, out, n, &n,
525 : DriverCompletion, 0);
526 1 : if (SQL_SUCCEEDED(rc)) {
527 1 : fixWcharOut(rc, out, n, OutConnectionString, BufferLength,
528 : StringLength2Ptr, 1, addDbcError, dbc);
529 : }
530 1 : free(out);
531 1 : if (in)
532 1 : free(in);
533 : return rc;
534 : }
|