tdbc::odbc

Check-in [492ee97daf]
Login
Bounty program for improvements to Tcl and certain Tcl packages.

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Improvements to new lib loader. Now also can handle a list of libs taken ie. from an env var.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 492ee97daf38a817810b655bd60c846971505e9d
User & Date: stu 2017-05-27 11:59:54
Context
2017-05-29
04:57
Fix inverted test in new loader. check-in: 986133b362 user: stu tags: trunk
2017-05-27
11:59
Improvements to new lib loader. Now also can handle a list of libs taken ie. from an env var. check-in: 492ee97daf user: stu tags: trunk
2017-05-26
23:17
Trying out a new lib loader, currently disabled. Hoping to bring this to the other TDBC-* drivers; their loaders could be more consistent with each other. Looking for feedback. check-in: 529b2be8a7 user: stu tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to generic/odbcStubInit.c.

27
28
29
30
31
32
33
34
35
36
37


38
39
40
41
42
43
44
...
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180

181


182
183
184
185











186
187
188

189
190

















































191
192
193
194

195
196
197




198
199
200
201
202
203
204
205
206

207
208
209


210

211
212

213
214

215
216

217
218
219
220


221
222
223
224
225
226
227
...
238
239
240
241
242
243
244

245
246
247
248
249
250
251
252
253
254
255
256

257



258
259
260
261
262
263
264
265
266
267
268
269
270
271
272

273



274
275
276
277
278
279
280
281
282
283
/*
 * Names of the libraries that might contain the ODBC API
 */


/* Uncomment or -DTDBC_NEW_LOADER=1 to use the new loader */
/* #define TDBC_NEW_LOADER 1*/


#ifdef TDBC_NEW_LOADER



/* Sorted by name asc. */
static const char *const odbcStubLibNames[] = {
    "iodbc", "odbc", "odbc32", NULL
};
/* Sorted by num desc. No leading dots. Empty first. */
static const char *const odbcStubLibNumbers[] = {
................................................................................
};

/*
 *-----------------------------------------------------------------------------
 *
 * tdbcLoadLib --
 *
 *	Tries to load a shared library using all combinations of
 *	LIBPREFIX, no LIBPREFIX, lib names and lib numbers.
 *	Takes CYGWIN into account.
 *
 * Results:
 *	Returns the handle to the loaded ODBC client library and leaves the
 *	name of the the loaded ODBC client library in the interpreter, or NULL
 *	if the load is unsuccessful and leaves a list of error message(s) in the
 *	interpreter.
 *
 *-----------------------------------------------------------------------------
 */

static Tcl_LoadHandle
tdbcLoadLib (
    Tcl_Interp *interp,
    const char *const soNames[],
    const char *const soNumbers[],
    const char *const soSymbolNames[],
    const void *soStubDefs,

    const char *const soFormats[]


) {
    const char *const *nam;
    const char *const *num;
    const char *const *fmt;











    Tcl_Obj *errors;
    Tcl_Obj *lib;
    Tcl_LoadHandle handle;

    int status;


















































    if (soFormats == NULL) {
	soFormats = tdbcLibFormats;
    }


    errors = Tcl_NewListObj(0, NULL);
    Tcl_IncrRefCount(errors);





    for (nam = &soNames[0]; *nam != NULL; nam++) {
	for (num = &soNumbers[0]; *num != NULL; num++) {
	    for (fmt = &soFormats[0]; *fmt != NULL; fmt++) {
		lib = Tcl_ObjPrintf(*fmt, *nam, (*num[0] == '\0' ? "" : TDBC_SHLIB_SEP), *num);
		Tcl_IncrRefCount(lib);
		handle = NULL;
		status = Tcl_LoadFile(interp, lib, soSymbolNames, 0, (void *) soStubDefs, &handle);
		if (status == TCL_OK) {
		    Tcl_SetObjResult(interp, lib);

		    Tcl_DecrRefCount(lib);
		    Tcl_DecrRefCount(errors);
		    return handle;


		}

		Tcl_DecrRefCount(lib);
		Tcl_ListObjAppendElement(NULL, errors, Tcl_GetObjResult(interp));

	    }
	}

    }


    Tcl_SetObjResult(interp, errors);
    Tcl_DecrRefCount(errors);

    return NULL;


}

/*
 *-----------------------------------------------------------------------------
 *
 * OdbcInitStubs --
 *
................................................................................
MODULE_SCOPE Tcl_LoadHandle
OdbcInitStubs(Tcl_Interp* interp,
				/* Tcl interpreter */
	      Tcl_LoadHandle* handle2Ptr)
				/* Pointer to a second load handle
				 * that represents the ODBCINST library */
{

    int odbcStatus;		/* Status of Tcl library calls */
    int odbcOptStatus;		/* Status of Tcl library calls */
    Tcl_LoadHandle handle;	/* Handle to a load module */

    SQLConfigDataSourceW = NULL;
    SQLConfigDataSource = NULL;
    SQLInstallerError = NULL;

    /*
     * Try to load a client library and resolve the ODBC API within it.
     */


    handle = tdbcLoadLib(interp, odbcStubLibNames, odbcStubLibNumbers, odbcSymbolNames, odbcStubs, NULL);



    odbcStatus = (handle == NULL ? TCL_ERROR : TCL_OK);

    /*
     * We've run out of library names (in which case odbcStatus==TCL_ERROR
     * and the error message reflects the last unsuccessful load attempt).
     */

    if (odbcStatus != TCL_OK) {
	return NULL;
    }

    /*
     * If a client library is found, then try to load ODBCINST as well.
     */


    *handle2Ptr = tdbcLoadLib(interp, odbcOptLibNames, odbcOptLibNumbers, NULL, NULL, NULL);



    odbcOptStatus = (*handle2Ptr == NULL ? TCL_ERROR : TCL_OK);

    if (odbcOptStatus == TCL_OK) {
	SQLConfigDataSourceW =
	    (BOOL (INSTAPI*)(HWND, WORD, LPCWSTR, LPCWSTR))
	    Tcl_FindSymbol(NULL, *handle2Ptr, "SQLConfigDataSourceW");
	if (SQLConfigDataSourceW == NULL) {
	    SQLConfigDataSource =
		(BOOL (INSTAPI*)(HWND, WORD, LPCSTR, LPCSTR))
		Tcl_FindSymbol(NULL, *handle2Ptr,






|



>
>







 







|
|













|
|
|
|
|
>
|
>
>

|
|
|
>
>
>
>
>
>
>
>
>
>
>
|
|
<
>
|

>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>




>
|
|
|
>
>
>
>
|
|
|
|
|
<
|
<
<
>
|
<
<
>
>
|
>
|
<
>
|
|
>
|
<
>
|
|
|
<
>
>







 







>
|
|
<

|







>
|
>
>
>
|


|



|







>
|
>
>
>
|

|







27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
...
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203

204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272

273


274
275


276
277
278
279
280

281
282
283
284
285

286
287
288
289

290
291
292
293
294
295
296
297
298
...
309
310
311
312
313
314
315
316
317
318

319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
/*
 * Names of the libraries that might contain the ODBC API
 */


/* Uncomment or -DTDBC_NEW_LOADER=1 to use the new loader */
/*#define TDBC_NEW_LOADER 1*/


#ifdef TDBC_NEW_LOADER

#include <stdlib.h>

/* Sorted by name asc. */
static const char *const odbcStubLibNames[] = {
    "iodbc", "odbc", "odbc32", NULL
};
/* Sorted by num desc. No leading dots. Empty first. */
static const char *const odbcStubLibNumbers[] = {
................................................................................
};

/*
 *-----------------------------------------------------------------------------
 *
 * tdbcLoadLib --
 *
 *	Tries to load a shared library given a list of lib names and/or
 *	all combinations of LIBPREFIX, no LIBPREFIX, lib names and lib numbers.
 *	Takes CYGWIN into account.
 *
 * Results:
 *	Returns the handle to the loaded ODBC client library and leaves the
 *	name of the the loaded ODBC client library in the interpreter, or NULL
 *	if the load is unsuccessful and leaves a list of error message(s) in the
 *	interpreter.
 *
 *-----------------------------------------------------------------------------
 */

static Tcl_LoadHandle
tdbcLoadLib (
    Tcl_Interp *interp,			/* Receives errors or lib name if successful */
    const char *const soNames[],	/* Lib names. Kwazy lookup not done if NULL */
    const char *const soNumbers[],	/* Lib numbers for kwazy lookup */
    const char *const soSymbolNames[],	/* Passed to Tcl_LoadFile */
    const void *soStubDefs,		/* Passed to Tcl_LoadFile */
    const char *soList,			/* Lib name list to try first if not NULL */
    const char *const soFormats[]	/* Lib name printf formats for kwazy lookup.
					   Default used if NULL.
					   Maybe not useful as a parameter. */
) {
    const char *const *nam;		/* Name */
    const char *const *num;		/* Number */
    const char *const *fmt;		/* Format */
    Tcl_Obj *lib;			/* Holds lib name during kwazy lookup */
    Tcl_Obj *result;			/* List of errors or lib name if successful */
    Tcl_LoadHandle handle;		/* NULL or handle to loaded lib if successful */

    result = NULL; /* Important! This is eventually returned. */
    handle = NULL; /* Important! This is eventually returned. */

    /*
     * Try to load a lib from a string claiming to be a list of libs?
     */
    if (soList != NULL) {	/* Yes! */
	Tcl_Obj *l;
	Tcl_Obj **els;

	int nels;
	int i;

	/*
         * Make list from string.
	 * Caller is responsible for listability and utf8ness.
         */
	l = Tcl_NewStringObj(soList, -1);
	Tcl_IncrRefCount(l);

	if (Tcl_ListObjGetElements(interp, l, &nels, &els) != TCL_OK) {
	    Tcl_DecrRefCount(l);
	    return NULL;
	}

	result = Tcl_NewListObj(0, NULL);
	Tcl_IncrRefCount(result);

	/*
	 * Left-to-right, trying to load a lib at each iteration.
         */
	for (i = 0; i < nels; i++) {
	    if (Tcl_LoadFile(interp, els[i], soSymbolNames, 0, (void *) soStubDefs, &handle) == TCL_OK) {
		/* Lib found and loaded. Cleanup and setup result. */
		Tcl_DecrRefCount(result); /* Throw away any accumulated errors. */
		result = Tcl_DuplicateObj(els[i]);
		Tcl_IncrRefCount(result);
		break;
	    }
	    Tcl_ListObjAppendElement(NULL, result, Tcl_GetObjResult(interp)); /* Collect error. */
	    handle = NULL; /* Important! This is eventually returned. */
	}
	Tcl_DecrRefCount(l);
	if (handle != NULL) {
	    goto loadDone;
	}
    }

    /*
     * At this point no lib list was provided or no lib was found in the list.
     */

    /*
     * Done if names not provided.
     */
    if (soNames == NULL) {
	goto loadDone;
    }

    /*
     * Use default format(s) if not supplied.
     */
    if (soFormats == NULL) {
	soFormats = tdbcLibFormats;
    }

    if (result != NULL) {
	result = Tcl_NewListObj(0, NULL);
	Tcl_IncrRefCount(result);
    }

    /*
     * Try every possible combination (aka Kwazy Lookup).
     */
    for (nam =   &soNames[0]; *nam != NULL; nam++) {
    for (num = &soNumbers[0]; *num != NULL; num++) {
    for (fmt = &soFormats[0]; *fmt != NULL; fmt++) {
	lib = Tcl_ObjPrintf(*fmt, *nam, (*num[0] == '\0' ? "" : TDBC_SHLIB_SEP), *num);
	Tcl_IncrRefCount(lib);

	if (Tcl_LoadFile(interp, lib, soSymbolNames, 0, (void *) soStubDefs, &handle) == TCL_OK) {


	    /* Lib found and loaded. Cleanup and setup result. */
	    Tcl_DecrRefCount(result); /* Throw away any accumulated errors. */


	    result = lib;
	    goto loadDone;
	}
	Tcl_ListObjAppendElement(NULL, result, Tcl_GetObjResult(interp)); /* Collect error. */
	Tcl_DecrRefCount(lib);

	handle = NULL; /* Important! This is eventually returned. */
    }}}

loadDone:


    if (result != NULL) {
	Tcl_SetObjResult(interp, result);
	Tcl_DecrRefCount(result);
    }


    return handle; /* Like I said... */
}

/*
 *-----------------------------------------------------------------------------
 *
 * OdbcInitStubs --
 *
................................................................................
MODULE_SCOPE Tcl_LoadHandle
OdbcInitStubs(Tcl_Interp* interp,
				/* Tcl interpreter */
	      Tcl_LoadHandle* handle2Ptr)
				/* Pointer to a second load handle
				 * that represents the ODBCINST library */
{
    Tcl_LoadHandle handle;	/* Handle to a load module */
    int status;			/* Status of Tcl library calls for ODBC lib */
    int status2;		/* Status of Tcl library calls for ODBCINST lib */


    SQLConfigDataSourceW = NULL;/* Symbols maybe in ODBCINST lib */
    SQLConfigDataSource = NULL;
    SQLInstallerError = NULL;

    /*
     * Try to load a client library and resolve the ODBC API within it.
     */

    handle = tdbcLoadLib(interp,
	odbcStubLibNames, odbcStubLibNumbers,
	odbcSymbolNames, odbcStubs,
	getenv("TDBC_ODBC_ODBCLIBS"), NULL
    );
    status = (handle == NULL ? TCL_ERROR : TCL_OK);

    /*
     * We've run out of library names (in which case status==TCL_ERROR
     * and the error message reflects the last unsuccessful load attempt).
     */

    if (status != TCL_OK) {
	return NULL;
    }

    /*
     * If a client library is found, then try to load ODBCINST as well.
     */

    *handle2Ptr = tdbcLoadLib(interp,
	odbcOptLibNames, odbcOptLibNumbers,
	NULL, NULL,
	getenv("TDBC_ODBC_ODBCINSTLIBS"), NULL
    );
    status2 = (*handle2Ptr == NULL ? TCL_ERROR : TCL_OK);

    if (status2 == TCL_OK) {
	SQLConfigDataSourceW =
	    (BOOL (INSTAPI*)(HWND, WORD, LPCWSTR, LPCWSTR))
	    Tcl_FindSymbol(NULL, *handle2Ptr, "SQLConfigDataSourceW");
	if (SQLConfigDataSourceW == NULL) {
	    SQLConfigDataSource =
		(BOOL (INSTAPI*)(HWND, WORD, LPCSTR, LPCSTR))
		Tcl_FindSymbol(NULL, *handle2Ptr,