LCOV - code coverage report
Current view: top level - clients/odbc/driver - SQLConnect.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 249 289 86.2 %
Date: 2024-10-07 21:21:43 Functions: 8 8 100.0 %

          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 (that's 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             :  * SQLConnect()
      25             :  * CLI Compliance: ISO 92
      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             : #include "ODBCAttrs.h"
      36             : #include <time.h>
      37             : #include "msettings.h"
      38             : #include "mstring.h"
      39             : 
      40             : #ifdef HAVE_ODBCINST_H
      41             : #include <odbcinst.h>
      42             : #endif
      43             : 
      44             : #ifndef HAVE_SQLGETPRIVATEPROFILESTRING
      45             : #define SQLGetPrivateProfileString(section,entry,default,buffer,bufferlen,filename)     ((int) strcpy_len(buffer,default,bufferlen))
      46             : #endif
      47             : 
      48             : static SQLRETURN
      49          32 : get_serverinfo(ODBCDbc *dbc)
      50             : {
      51          32 :         MapiHdl hdl = NULL;
      52          32 :         SQLRETURN rc; // intentionally uninitialized
      53          32 :         char *n, *v;
      54             : 
      55          32 :         if ((hdl = mapi_query(dbc->mid, "select name, value from sys.env() where name in ('monet_version', 'gdk_dbname', 'max_clients', 'raw_strings')")) == NULL)
      56           0 :                 goto end;
      57          32 :         dbc->raw_strings = false;
      58         160 :         while (mapi_fetch_row(hdl)) {
      59         128 :                 n = mapi_fetch_field(hdl, 0);
      60         128 :                 v = mapi_fetch_field(hdl, 1);
      61         128 :                 if (strcmp(n, "monet_version") == 0) {
      62          32 :                         sscanf(v, "%hd.%hd.%hd",
      63             :                                &dbc->major, &dbc->minor, &dbc->patch);
      64             :                 } else
      65          96 :                 if (strcmp(n, "max_clients") == 0) {
      66          32 :                         sscanf(v, "%hu", &dbc->maxclients);
      67          64 :                 } else if (strcmp(n, "raw_strings") == 0) {
      68          32 :                         dbc->raw_strings = strcmp(v, "true") == 0;
      69             :                 } else {
      70          32 :                         assert(strcmp(n, "gdk_dbname") == 0);
      71          32 :                         msetting_set_string(dbc->settings, MP_DATABASE, v);
      72             :                 }
      73             :         }
      74          32 :         if (mapi_error(dbc->mid))
      75           0 :                 goto end;
      76          32 :         mapi_close_handle(hdl);
      77          32 :         if ((hdl = mapi_query(dbc->mid, "select id from sys._tables where name = 'comments' and schema_id = (select id from sys.schemas where name = 'sys')")) == NULL)
      78           0 :                 goto end;
      79          32 :         if (mapi_error(dbc->mid))
      80           0 :                 goto end;
      81             :         n = NULL;
      82          64 :         while (mapi_fetch_row(hdl)) {
      83          32 :                 n = mapi_fetch_field(hdl, 0);
      84             :         }
      85          32 :         dbc->has_comment = n != NULL;
      86             : 
      87          32 :         rc = SQL_SUCCESS;
      88          32 : end:
      89          32 :         if (mapi_error(dbc->mid)) {
      90           0 :                 addDbcError(dbc, "08001", mapi_error_str(dbc->mid), 0);
      91           0 :                 rc = SQL_ERROR;
      92             :         }
      93          32 :         mapi_close_handle(hdl);
      94          32 :         return rc;
      95             : }
      96             : 
      97             : 
      98             : // Ensure '*argument' is either NULL or a NUL-terminated string,
      99             : // taking into account 'argument_len' being either a proper string length
     100             : // or one of the special values SQL_NULL_DATA or SQL_NTS.
     101             : //
     102             : // Return 'true' on success and 'false' on allocation failure.
     103             : //
     104             : // If memory needs to be allocated and 'scratch' is not NULL,
     105             : // a pointer to the allocated memory will be stored in '*scratch'
     106             : // and the previous value of '*scratch' will be free'd.
     107             : //
     108             : // '*argument' is never free'd.
     109             : bool
     110          47 : makeNulTerminated(const SQLCHAR **argument, ssize_t argument_len, void **scratch)
     111             : {
     112          47 :         assert(argument != NULL);
     113             : 
     114          47 :         if (*argument == NULL || argument_len == SQL_NTS)
     115             :                 return true;
     116           2 :         if (argument_len == SQL_NULL_DATA) {
     117           0 :                 *argument = NULL;
     118           0 :                 return true;
     119             :         }
     120             : 
     121           2 :         SQLCHAR *value = malloc(argument_len + 1);
     122           2 :         if (value == NULL)
     123             :                 return false;
     124           2 :         memmove(value, *argument, argument_len);
     125           2 :         value[argument_len] = '\0';
     126             : 
     127           2 :         *argument = value;
     128           2 :         if (scratch) {
     129           2 :                 free(*scratch);
     130           2 :                 *scratch = value;
     131             :         }
     132             : 
     133             :         return value;
     134             : }
     135             : 
     136             : char*
     137          43 : buildConnectionString(const char *dsn, const msettings *settings)
     138             : {
     139             : 
     140          43 :         size_t pos = 0;
     141          43 :         size_t cap = 1024;
     142          43 :         char *buf = malloc(cap);  // reallocprintf will deal with allocation failures
     143          43 :         char *sep = "";
     144          43 :         char *value = NULL;
     145          43 :         char *default_value = NULL;
     146          43 :         bool ok = false;
     147             : 
     148          43 :         if (dsn) {
     149          43 :                 if (reallocprintf(&buf, &pos, &cap, "DSN=%s", dsn) < 0)
     150           0 :                         goto end;
     151             :                 sep = ";";
     152             :         }
     153             : 
     154         989 :         for (int i = 0; i < attr_setting_count; i++) {
     155         946 :                 const struct attr_setting *entry = &attr_settings[i];
     156         946 :                 mparm parm = entry->parm;
     157             : 
     158         946 :                 if (parm == MP_IGNORE || parm == MP_TABLE || parm == MP_TABLESCHEMA)
     159           0 :                         continue;
     160             : 
     161         946 :                 free(value);
     162         946 :                 value = msetting_as_string(settings, parm);
     163         946 :                 if (!value)
     164           0 :                         goto end;
     165             : 
     166         946 :                 bool show_this;  // intentionally uninitialized
     167         946 :                 if (parm == MP_USER || parm == MP_PASSWORD) {
     168             :                         show_this = true;
     169         860 :                 } else if (parm == MP_PORT && msetting_long(settings, MP_PORT) <= 0) {
     170             :                         show_this = false;
     171         854 :                 } else if (parm == MP_TLS) {
     172          43 :                         show_this = msetting_bool(settings, MP_TLS);
     173         811 :                 } else if (mparm_is_core(parm)) {
     174             :                         show_this = true;
     175             :                 } else {
     176             :                         // skip if still default
     177         688 :                         free(default_value);
     178         688 :                         default_value = msetting_as_string(msettings_default, parm);
     179         688 :                         if (!default_value)
     180           0 :                                 goto end;
     181         688 :                         show_this = (strcmp(value, default_value) != 0);
     182             :                 }
     183         731 :                 if (show_this) {
     184         217 :                         if (reallocprintf(&buf, &pos, &cap, "%s%s=%s", sep, entry->name, value) < 0)
     185           0 :                                 goto end;
     186             :                         sep = ";";
     187             :                 }
     188             :         }
     189             : 
     190             :         ok = true;
     191             : 
     192          43 : end:
     193          43 :         free(value);
     194          43 :         free(default_value);
     195          43 :         if (ok) {
     196          43 :                 return buf;
     197             :         } else {
     198           0 :                 free(buf);
     199           0 :                 return NULL;
     200             :         }
     201             : }
     202             : 
     203             : static int
     204         814 : lookup(const char *dsn, const struct attr_setting *entry, char *buf, int bufsize)
     205             : {
     206         814 :         int n;
     207         814 :         assert(entry->name);
     208         814 :         n = SQLGetPrivateProfileString(dsn, entry->name, "", buf, bufsize, "odbc.ini");
     209         814 :         if (n > 0)
     210             :                 return n;
     211         703 :         if (entry->alt_name)
     212         666 :                 n = SQLGetPrivateProfileString(dsn, entry->alt_name, "", buf, bufsize, "odbc.ini");
     213             :         return n;
     214             : }
     215             : 
     216             : const char*
     217          37 : takeFromDataSource(ODBCDbc *dbc, msettings *settings, const char *dsn)
     218             : {
     219          37 :         char buf[1024] = { 0 };
     220             : 
     221         851 :         for (int i = 0; i < attr_setting_count; i++) {
     222         814 :                 const struct attr_setting *entry = &attr_settings[i];
     223         814 :                 mparm parm = entry->parm;
     224         814 :                 int n = lookup(dsn, entry, buf, sizeof(buf));
     225         814 :                 if (n > 0) {
     226         185 :                         if (sizeof(buf) - n <= 1)
     227             :                                 return "01004"; // truncated
     228         185 :                         const char *msg = msetting_parse(settings, parm, buf);
     229         185 :                         if (msg != NULL)
     230           0 :                                 return msg;
     231         185 :                         dbc->setting_touched[(int)parm] = 1;
     232             :                 }
     233             :         }
     234             : 
     235             :         return NULL;
     236             : }
     237             : 
     238             : SQLRETURN
     239          29 : takeFromConnString(
     240             :         ODBCDbc *dbc,
     241             :         msettings *settings,
     242             :         const SQLCHAR *InConnectionString,
     243             :         SQLSMALLINT StringLength1,
     244             :         char **dsn_out)
     245             : {
     246          29 :         SQLRETURN rc = SQL_SUCCESS;
     247          29 :         const char *sqlstate = NULL;
     248          29 :         const char *sql_explanation = NULL;
     249          29 :         const SQLCHAR *cursor;
     250          29 :         SQLSMALLINT n;
     251          29 :         char *dsn = NULL, *key = NULL, *attr = NULL;
     252             : 
     253             :         // figure out the DSN and load its settings
     254          29 :         cursor = InConnectionString;
     255          29 :         n = StringLength1;
     256          56 :         while (ODBCGetKeyAttr(&cursor, &n, &key, &attr) > 0) {
     257          48 :                 if (strcasecmp(key, "dsn") == 0) {
     258          21 :                         dsn = attr;
     259          21 :                         free(key);
     260          21 :                         break;
     261             :                 }
     262          27 :                 free(key);
     263          27 :                 free(attr);
     264             :         }
     265          29 :         key = NULL;
     266          29 :         attr = NULL;
     267          29 :         if (dsn) {
     268          21 :                 if (strlen(dsn) > SQL_MAX_DSN_LENGTH)
     269             :                         sqlstate = "IM010";    // Data source name too long
     270             :                 else
     271          21 :                         sqlstate = takeFromDataSource(dbc, settings, dsn);
     272             :         }
     273          21 :         if (sqlstate)
     274           0 :                 goto end;
     275             : 
     276             :         // Override with settings from the connect string itself
     277          29 :         cursor = InConnectionString;
     278          29 :         n = StringLength1;
     279          92 :         while (ODBCGetKeyAttr(&cursor, &n, &key, &attr) > 0) {
     280          63 :                 int i = attr_setting_lookup(key, true);
     281          63 :                 if (i >= 0) {
     282          34 :                         mparm parm = attr_settings[i].parm;
     283          34 :                         sql_explanation = msetting_parse(settings, parm, attr);
     284          34 :                         if (sql_explanation)
     285           0 :                                 goto end;
     286          34 :                         dbc->setting_touched[(int)parm] = 1;
     287             :                 }
     288          63 :                 free(key);
     289          63 :                 free(attr);
     290             :         }
     291          29 :         key = NULL;
     292          29 :         attr = NULL;
     293             : 
     294          29 :         if (dsn && dsn_out) {
     295          21 :                 *dsn_out = dsn;
     296          21 :                 dsn = NULL;
     297             :         }
     298             : 
     299           8 : end:
     300          29 :         if (sql_explanation && !sqlstate)
     301             :                 sqlstate = "HY009";
     302          29 :         if (sqlstate) {
     303           0 :                 addDbcError(dbc, sqlstate, sql_explanation, 0);
     304           0 :                 rc = SQL_ERROR;
     305             :         }
     306          29 :         free(key);
     307          29 :         free(attr);
     308          29 :         free(dsn);
     309          29 :         return rc;
     310             : }
     311             : 
     312             : 
     313             : SQLRETURN
     314          16 : MNDBConnect(ODBCDbc *dbc,
     315             :             const SQLCHAR *ServerName,
     316             :             SQLSMALLINT NameLength1,
     317             :             const SQLCHAR *UserName,
     318             :             SQLSMALLINT NameLength2,
     319             :             const SQLCHAR *Authentication,
     320             :             SQLSMALLINT NameLength3)
     321             : {
     322             :         // These will be passed to addDbcError if you 'goto failure'.
     323             :         // If unset, 'goto failure' will assume an allocation error.
     324          16 :         const char *error_state = NULL;
     325          16 :         const char *error_explanation = NULL;
     326          16 :         SQLRETURN ret = SQL_ERROR;
     327             : 
     328             :         // These will be free'd / destroyed at the 'end' label at the bottom of this function
     329          16 :         char *dsn = NULL;
     330          16 :         msettings *settings = NULL;
     331          16 :         void *scratch = NULL;
     332             : 
     333             :         // These do not need to be free'd
     334          16 :         const char *mapiport_env;
     335             : 
     336             :         // Check connection state, should not be connected
     337          16 :         if (dbc->Connected) {
     338           0 :                 error_state = "08002";
     339           0 :                 goto failure;
     340             :         }
     341             : 
     342             :         // Modify a copy so the original remains unchanged when we return an error
     343          16 :         settings = msettings_clone(dbc->settings);
     344          16 :         if (settings == NULL)
     345           0 :                 goto failure;
     346             : 
     347             :         // ServerName is really the Data Source name
     348          16 :         if (!makeNulTerminated(&ServerName, NameLength1, &scratch))
     349           0 :                 goto failure;
     350          16 :         if (ServerName != NULL) {
     351          16 :                 dsn = strdup((char*)ServerName);
     352          16 :                 if (dsn == NULL)
     353           0 :                         goto failure;
     354             :         }
     355             : 
     356             :         // data source settings take precedence over existing ones
     357          16 :         if (dsn && *dsn) {
     358          16 :                 error_state = takeFromDataSource(dbc, settings, dsn);
     359          16 :                 if (error_state != NULL)
     360           0 :                         goto failure;
     361             :         }
     362             : 
     363             : #ifdef ODBCDEBUG
     364          16 :         if (ODBCdebug == NULL || *ODBCdebug == 0) {
     365          16 :                 const char *logfile = msetting_string(settings, MP_LOGFILE);
     366          16 :                 if (*logfile)
     367           0 :                         setODBCdebug(logfile, true);
     368             :         }
     369             : #endif
     370             : 
     371             :         // The dedicated parameters for user name, password, host, port and database name
     372             :         // override the pre-existing values and whatever came from the data source.
     373             :         // We also take the MAPIPORT environment variable into account.
     374             : 
     375          16 :         if (!makeNulTerminated(&UserName, NameLength2, &scratch))
     376           0 :                 goto failure;
     377          16 :         if (UserName) {
     378          11 :                 if (!*UserName) {
     379           1 :                         error_state = "28000";
     380           1 :                         error_explanation = "user name not set";
     381           1 :                         goto failure;
     382             :                 }
     383          10 :                 error_explanation = msetting_set_string(settings, MP_USER, (char*)UserName);
     384          10 :                 if (error_explanation != NULL)
     385           0 :                         goto failure;
     386             :         }
     387             : 
     388          15 :         if (!makeNulTerminated(&Authentication, NameLength3, &scratch))
     389           0 :                 goto failure;
     390          15 :         if (Authentication) {
     391          11 :                 if (!*Authentication) {
     392           1 :                         error_state = "28000";
     393           1 :                         error_explanation = "password not set";
     394           1 :                         goto failure;
     395             :                 }
     396          10 :                 error_explanation = msetting_set_string(settings, MP_PASSWORD, (char*)Authentication);
     397          10 :                 if (error_explanation != NULL)
     398           0 :                         goto failure;
     399             :         }
     400             : 
     401          14 :         mapiport_env = getenv("MAPIPORT");
     402          14 :         if (mapiport_env != NULL)
     403          14 :                 error_explanation = msetting_parse(settings, MP_PORT, mapiport_env);
     404          14 :         if (error_explanation != NULL)
     405           0 :                 goto failure;
     406             : 
     407             : #ifdef ODBCDEBUG
     408             :         {
     409          14 :                 free(scratch);
     410          14 :                 char *connstring = scratch = buildConnectionString(dsn, settings);
     411          14 :                 if (!connstring)
     412           0 :                         goto failure;
     413          14 :                 ODBCLOG("SQLConnect: %s\n", connstring);
     414             :         }
     415             : #endif
     416             : 
     417          14 :         assert(error_state == NULL);
     418          14 :         assert(error_explanation == NULL);
     419             : 
     420          14 :         ret = MNDBConnectSettings(dbc, dsn, settings);
     421          14 :         settings = NULL; // must not be free'd now
     422             : 
     423          14 :         goto end;
     424             : 
     425           2 : failure:
     426           2 :         if (error_state == NULL) {
     427           0 :                 if (error_explanation == NULL || msettings_malloc_failed(error_explanation))
     428             :                         error_state = "HY001"; // allocation failure
     429             :                 else
     430             :                         error_state = "HY009"; // invalid argument
     431             :         }
     432           2 :         addDbcError(dbc, error_state, error_explanation, 0);
     433             : 
     434             :         // fallthrough
     435          16 : end:
     436          16 :         free(dsn);
     437          16 :         free(scratch);
     438          16 :         msettings_destroy(settings);
     439             : 
     440          16 :         return ret;
     441             : }
     442             : 
     443             : SQLRETURN
     444          40 : MNDBConnectSettings(ODBCDbc *dbc, const char *dsn, msettings *settings)
     445             : {
     446          40 :         SQLRETURN rc;
     447          40 :         msettings *clone = msettings_clone(settings);
     448             : 
     449          40 :         if (clone == NULL) {
     450           0 :                 addDbcError(dbc, "HY001", NULL, 0);
     451           0 :                 return SQL_ERROR;
     452             :         }
     453             : 
     454          40 :         Mapi mid = mapi_settings(settings);
     455          40 :         if (mid) {
     456          40 :                 settings = NULL; // will be free'd as part of 'mid' now
     457          40 :                 mapi_setclientprefix(mid, "ODBC " MONETDB_VERSION);
     458          40 :                 mapi_set_size_header(mid, true);
     459          40 :                 mapi_reconnect(mid);
     460             :         }
     461          40 :         if (mid == NULL || mapi_error(mid)) {
     462           8 :                 const char *error_state = "08001";
     463           8 :                 const char *error_explanation = mid ? mapi_error_str(mid) : NULL;
     464           8 :                 if (error_explanation) {
     465           8 :                         if (strncmp(error_explanation, "InvalidCredentialsException:", 28) == 0)
     466             :                                 error_state = "28000";
     467             :                         else
     468           5 :                         if (strncmp(error_explanation, "could not connect: Connection timed out", 39) == 0)
     469           0 :                                 error_state = "HYT00";
     470             :                 }
     471           8 :                 addDbcError(dbc, error_state, error_explanation, 0);
     472           8 :                 if (mid)
     473           8 :                         mapi_destroy(mid);
     474           8 :                 msettings_destroy(settings);
     475           8 :                 msettings_destroy(clone);
     476           8 :                 return SQL_ERROR;
     477             :         }
     478             : 
     479          32 :         free(dbc->dsn);
     480          32 :         dbc->dsn = dsn ? strdup(dsn) : NULL;
     481             : 
     482          32 :         if (dbc->mid)
     483           0 :                 mapi_destroy(dbc->mid);
     484          32 :         dbc->mid = mid;
     485             : 
     486          32 :         msettings_destroy(dbc->settings);
     487          32 :         dbc->settings = clone;
     488             : 
     489          32 :         dbc->mapToLongVarchar = msetting_long(dbc->settings, MP_MAPTOLONGVARCHAR);
     490             : 
     491          32 :         dbc->Connected = true;
     492             : 
     493          32 :         rc = get_serverinfo(dbc);
     494          32 :         if (!SQL_SUCCEEDED(rc))
     495           0 :                 return rc;
     496             : 
     497             :         return SQL_SUCCESS;
     498             : }
     499             : 
     500             : 
     501             : 
     502             : 
     503             : SQLRETURN SQL_API
     504             : SQLConnect(SQLHDBC ConnectionHandle,
     505             :            SQLCHAR *ServerName,
     506             :            SQLSMALLINT NameLength1,
     507             :            SQLCHAR *UserName,
     508             :            SQLSMALLINT NameLength2,
     509             :            SQLCHAR *Authentication,
     510             :            SQLSMALLINT NameLength3)
     511             : {
     512             : #ifdef ODBCDEBUG
     513          14 :         ODBCLOG("SQLConnect %p\n", ConnectionHandle);
     514             : #endif
     515             : 
     516          14 :         if (!isValidDbc((ODBCDbc *) ConnectionHandle))
     517             :                 return SQL_INVALID_HANDLE;
     518             : 
     519          14 :         clearDbcErrors((ODBCDbc *) ConnectionHandle);
     520             : 
     521          14 :         return MNDBConnect((ODBCDbc *) ConnectionHandle,
     522             :                            ServerName, NameLength1,
     523             :                            UserName, NameLength2,
     524             :                            Authentication, NameLength3);
     525             : }
     526             : 
     527             : SQLRETURN SQL_API
     528             : SQLConnectA(SQLHDBC ConnectionHandle,
     529             :             SQLCHAR *ServerName,
     530             :             SQLSMALLINT NameLength1,
     531             :             SQLCHAR *UserName,
     532             :             SQLSMALLINT NameLength2,
     533             :             SQLCHAR *Authentication,
     534             :             SQLSMALLINT NameLength3)
     535             : {
     536           0 :         return SQLConnect(ConnectionHandle,
     537             :                           ServerName, NameLength1,
     538             :                           UserName, NameLength2,
     539             :                           Authentication, NameLength3);
     540             : }
     541             : 
     542             : SQLRETURN SQL_API
     543             : SQLConnectW(SQLHDBC ConnectionHandle,
     544             :             SQLWCHAR *ServerName,
     545             :             SQLSMALLINT NameLength1,
     546             :             SQLWCHAR *UserName,
     547             :             SQLSMALLINT NameLength2,
     548             :             SQLWCHAR *Authentication,
     549             :             SQLSMALLINT NameLength3)
     550             : {
     551           2 :         SQLCHAR *ds = NULL, *uid = NULL, *pwd = NULL;
     552           2 :         SQLRETURN rc = SQL_ERROR;
     553           2 :         ODBCDbc *dbc = (ODBCDbc *) ConnectionHandle;
     554             : 
     555             : #ifdef ODBCDEBUG
     556           2 :         ODBCLOG("SQLConnectW %p\n", ConnectionHandle);
     557             : #endif
     558             : 
     559           2 :         if (!isValidDbc(dbc))
     560             :                 return SQL_INVALID_HANDLE;
     561             : 
     562           2 :         clearDbcErrors(dbc);
     563             : 
     564           2 :         fixWcharIn(ServerName, NameLength1, SQLCHAR, ds,
     565             :                    addDbcError, dbc, goto bailout);
     566           2 :         fixWcharIn(UserName, NameLength2, SQLCHAR, uid,
     567             :                    addDbcError, dbc, goto bailout);
     568           2 :         fixWcharIn(Authentication, NameLength3, SQLCHAR, pwd,
     569             :                    addDbcError, dbc, goto bailout);
     570             : 
     571           2 :         rc = MNDBConnect(dbc,
     572             :                          ds, SQL_NTS,
     573             :                          uid, SQL_NTS,
     574             :                          pwd, SQL_NTS);
     575             : 
     576           2 :       bailout:
     577           2 :         if (ds)
     578           2 :                 free(ds);
     579           2 :         if (uid)
     580           2 :                 free(uid);
     581           2 :         if (pwd)
     582           2 :                 free(pwd);
     583             :         return rc;
     584             : }

Generated by: LCOV version 1.14