tdbc::odbc

Check-in [529b2be8a7]
Login
Bounty program for improvements to Tcl and certain Tcl packages.
Tcl 2019 Conference, Houston/TX, US, Nov 4-8
Send your abstracts to [email protected]
or submit via the online form by Sep 9.

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

Overview
Comment: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.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 529b2be8a762e61ec9fa773aa0763cc2cd48e80e
User & Date: stu 2017-05-26 23:17:59
Context
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
18:39
rm -f not needed before ${INSTALL_*}. A ghost of past installing. check-in: 55b3958e61 user: stu tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to configure.

6119
6120
6121
6122
6123
6124
6125










6126
6127
6128
6129
6130
6131
6132
	if test ! -f "${srcdir}/$i" ; then
	    as_fn_error $? "could not find tcl source file '${srcdir}/$i'" "$LINENO" 5
	fi
	PKG_TCL_SOURCES="$PKG_TCL_SOURCES $i"
    done













#--------------------------------------------------------------------
#
# You can add more files to clean if your extension creates any extra
# files by extending CLEANFILES.
# Add pkgIndex.tcl if it is generated in the Makefile instead of ./configure
# and change Makefile.in to move it from CONFIG_CLEAN_FILES to BINARIES var.






>
>
>
>
>
>
>
>
>
>







6119
6120
6121
6122
6123
6124
6125
6126
6127
6128
6129
6130
6131
6132
6133
6134
6135
6136
6137
6138
6139
6140
6141
6142
	if test ! -f "${srcdir}/$i" ; then
	    as_fn_error $? "could not find tcl source file '${srcdir}/$i'" "$LINENO" 5
	fi
	PKG_TCL_SOURCES="$PKG_TCL_SOURCES $i"
    done



#--------------------------------------------------------------------
# The new loader needs to know the shared lib suffix.
#--------------------------------------------------------------------


cat >>confdefs.h <<_ACEOF
#define TCL_SHLIB_EXT "${TCL_SHLIB_SUFFIX}"
_ACEOF


#--------------------------------------------------------------------
#
# You can add more files to clean if your extension creates any extra
# files by extending CLEANFILES.
# Add pkgIndex.tcl if it is generated in the Makefile instead of ./configure
# and change Makefile.in to move it from CONFIG_CLEAN_FILES to BINARIES var.

Changes to configure.ac.

115
116
117
118
119
120
121







122
123
124
125
126
127
128
    TEA_ADD_LIBS([\"`${CYGPATH} ${tdbc_STUB_LIB_PATH}`\"])
else
    TEA_ADD_LIBS([${tdbc_STUB_LIB_SPEC}])
fi
TEA_ADD_CFLAGS([${tdbc_CFLAGS}])
TEA_ADD_STUB_SOURCES()
TEA_ADD_TCL_SOURCES([library/tdbcodbc.tcl])








#--------------------------------------------------------------------
#
# You can add more files to clean if your extension creates any extra
# files by extending CLEANFILES.
# Add pkgIndex.tcl if it is generated in the Makefile instead of ./configure
# and change Makefile.in to move it from CONFIG_CLEAN_FILES to BINARIES var.






>
>
>
>
>
>
>







115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
    TEA_ADD_LIBS([\"`${CYGPATH} ${tdbc_STUB_LIB_PATH}`\"])
else
    TEA_ADD_LIBS([${tdbc_STUB_LIB_SPEC}])
fi
TEA_ADD_CFLAGS([${tdbc_CFLAGS}])
TEA_ADD_STUB_SOURCES()
TEA_ADD_TCL_SOURCES([library/tdbcodbc.tcl])

#--------------------------------------------------------------------
# The new loader needs to know the shared lib suffix.
#--------------------------------------------------------------------

AC_DEFINE_UNQUOTED(TCL_SHLIB_EXT,"${TCL_SHLIB_SUFFIX}",
    [What is the default extension for shared libraries?])

#--------------------------------------------------------------------
#
# You can add more files to clean if your extension creates any extra
# files by extending CLEANFILES.
# Add pkgIndex.tcl if it is generated in the Makefile instead of ./configure
# and change Makefile.in to move it from CONFIG_CLEAN_FILES to BINARIES var.

Changes to generic/odbcStubInit.c.

25
26
27
28
29
30
31


























32
33
34
35
36
37
38
39
40



41
42
43
44
45
46
47
..
93
94
95
96
97
98
99













































































































































































100
101
102
103
104
105
106
...
195
196
197
198
199
200
201

 * Static data used in this file
 */

/*
 * Names of the libraries that might contain the ODBC API
 */



























static const char *const odbcStubLibNames[] = {
    /* @[email protected]: DO NOT EDIT THESE NAMES */
    "odbc32", "odbc", "libodbc32", "libodbc", "libiodbc", NULL
    /* @[email protected] */
};
static const char *const odbcOptLibNames[] = {
    "odbccp", "odbccp32", "odbcinst",
    "libodbccp", "libodbccp32", "libodbcinst", "libiodbcinst", NULL
};




/*
 * Names of the functions that we need from ODBC
 */

static const char *const odbcSymbolNames[] = {
    /* @[email protected]: DO NOT EDIT THESE NAMES */
................................................................................
BOOL (INSTAPI* SQLConfigDataSourceW)(HWND, WORD, LPCWSTR, LPCWSTR)
= NULL;
BOOL (INSTAPI* SQLConfigDataSource)(HWND, WORD, LPCSTR, LPCSTR)
= NULL;
BOOL (INSTAPI* SQLInstallerError)(WORD, DWORD*, LPSTR, WORD, WORD*)
= NULL;














































































































































































/*
 *-----------------------------------------------------------------------------
 *
 * OdbcInitStubs --
 *
 *	Initialize the Stubs table for the ODBC API
 *
................................................................................
    Tcl_DecrRefCount(shlibext);
    if (status != TCL_OK) {
	return NULL;
    }
    return handle;
}








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









>
>
>







 







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







 







>
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
...
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
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
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
299
300
301
302
303
304
305
306
307
308
...
397
398
399
400
401
402
403
404
 * Static data used in this file
 */

/*
 * 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[] = {
	"", "1.2", "0.1", NULL
};
/* Sorted by name asc. */
static const char *const odbcOptLibNames[] = {
    "iodbcinst", "odbccp", "odbccp32", "odbcinst", NULL
};
/* Sorted by num desc. No leading dots. Empty first. */
static const char *const odbcOptLibNumbers[] = {
	"", "2.6", "0.0", NULL
};

#else

static const char *const odbcStubLibNames[] = {
    /* @[email protected]: DO NOT EDIT THESE NAMES */
    "odbc32", "odbc", "libodbc32", "libodbc", "libiodbc", NULL
    /* @[email protected] */
};
static const char *const odbcOptLibNames[] = {
    "odbccp", "odbccp32", "odbcinst",
    "libodbccp", "libodbccp32", "libodbcinst", "libiodbcinst", NULL
};

#endif


/*
 * Names of the functions that we need from ODBC
 */

static const char *const odbcSymbolNames[] = {
    /* @[email protected]: DO NOT EDIT THESE NAMES */
................................................................................
BOOL (INSTAPI* SQLConfigDataSourceW)(HWND, WORD, LPCWSTR, LPCWSTR)
= NULL;
BOOL (INSTAPI* SQLConfigDataSource)(HWND, WORD, LPCSTR, LPCSTR)
= NULL;
BOOL (INSTAPI* SQLInstallerError)(WORD, DWORD*, LPSTR, WORD, WORD*)
= NULL;


#ifdef TDBC_NEW_LOADER

#ifndef TCL_SHLIB_EXT
#  define TCL_SHLIB_EXT ".so"
#endif

#ifndef LIBPREFIX
#  ifdef __CYGWIN__
#    define LIBPREFIX "cyg"
#  else
#    define LIBPREFIX "lib"
#  endif
#endif

#ifdef __CYGWIN__
#  define TDBC_SHLIB_SEP "-"
#else
#  define TDBC_SHLIB_SEP "."
#endif

const char *const tdbcLibFormats[] = {
	LIBPREFIX "%s" TCL_SHLIB_EXT "%s" "%s",
	"%s" TCL_SHLIB_EXT "%s" "%s",
	NULL
};

/*
 *-----------------------------------------------------------------------------
 *
 * 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 --
 *
 *	Initialize the Stubs table for the ODBC API
 *
 * Results:
 *	Returns the handle to the loaded ODBC client library, or NULL
 *	if the load is unsuccessful. Leaves an error message in the
 *	interpreter.
 *
 *-----------------------------------------------------------------------------
 */

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,
			       "SQLConfigDataSource");
	}
	SQLInstallerError =
	    (BOOL (INSTAPI*)(WORD, DWORD*, LPSTR, WORD, WORD*))
	    Tcl_FindSymbol(NULL, *handle2Ptr, "SQLInstallerError");
    } else {
	Tcl_ResetResult(interp);
    }

    /*
     * We've successfully loaded a library.
     */

    return handle;
}

#else

/*
 *-----------------------------------------------------------------------------
 *
 * OdbcInitStubs --
 *
 *	Initialize the Stubs table for the ODBC API
 *
................................................................................
    Tcl_DecrRefCount(shlibext);
    if (status != TCL_OK) {
	return NULL;
    }
    return handle;
}

#endif