tdbc::odbc

Check-in [d24d568a62]
Login

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

Overview
Comment:Reduce number of compiler warnings
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | trunk | main
Files: files | file ages | folders
SHA3-256: d24d568a6259b5d3863def17b697ff61ac215c7adaf24a7fcda8962f05034783
User & Date: jan.nijtmans 2025-08-15 16:12:00.881
Context
2025-08-15
16:12
Reduce number of compiler warnings Leaf check-in: d24d568a62 user: jan.nijtmans tags: trunk, main
2025-07-25
19:18
version -> 1.1.12 check-in: 23bf7e5437 user: dgp tags: trunk, main, tdbcodbc-1-1-12
Changes
Unified Diff Ignore Whitespace Patch
Changes to Makefile.in.
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
# We need to enumerate the list of .c to .o lines here.
#
# In the following lines, $(srcdir) refers to the toplevel directory
# containing your extension.  If your sources are in a subdirectory,
# you will have to modify the paths to reflect this:
#
# sample.$(OBJEXT): $(srcdir)/generic/sample.c
# 	$(COMPILE) -c `@CYGPATH@ $(srcdir)/generic/sample.c` -o $@
#
# Setting the VPATH variable to a list of paths will cause the makefile
# to look into these paths when resolving .c to .obj dependencies.
# As necessary, add $(srcdir):$(srcdir)/compat:....
#========================================================================

VPATH = $(srcdir):$(srcdir)/generic:$(srcdir)/unix:$(srcdir)/win







|







315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
# We need to enumerate the list of .c to .o lines here.
#
# In the following lines, $(srcdir) refers to the toplevel directory
# containing your extension.  If your sources are in a subdirectory,
# you will have to modify the paths to reflect this:
#
# sample.$(OBJEXT): $(srcdir)/generic/sample.c
#	$(COMPILE) -c `@CYGPATH@ $(srcdir)/generic/sample.c` -o $@
#
# Setting the VPATH variable to a list of paths will cause the makefile
# to look into these paths when resolving .c to .obj dependencies.
# As necessary, add $(srcdir):$(srcdir)/compat:....
#========================================================================

VPATH = $(srcdir):$(srcdir)/generic:$(srcdir)/unix:$(srcdir)/win
Changes to generic/fakesql.h.
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
 * Additional entry points in ODBCINST - all of these are optional
 * and resolved with Tcl_FindSymbol, not directly in Tcl_LoadLibrary.
 */

MODULE_SCOPE BOOL (INSTAPI* SQLConfigDataSourceW)(HWND, WORD, LPCWSTR,
						  LPCWSTR);
MODULE_SCOPE BOOL (INSTAPI* SQLConfigDataSource)(HWND, WORD, LPCSTR, LPCSTR);
MODULE_SCOPE BOOL (INSTAPI* SQLInstallerErrorW)(WORD, DWORD*, LPWSTR, WORD,
						WORD*);
MODULE_SCOPE BOOL (INSTAPI* SQLInstallerError)(WORD, DWORD*, LPSTR, WORD,
					       WORD*);

/*
 * Function that initialises the stubs
 */








<
<







265
266
267
268
269
270
271


272
273
274
275
276
277
278
 * Additional entry points in ODBCINST - all of these are optional
 * and resolved with Tcl_FindSymbol, not directly in Tcl_LoadLibrary.
 */

MODULE_SCOPE BOOL (INSTAPI* SQLConfigDataSourceW)(HWND, WORD, LPCWSTR,
						  LPCWSTR);
MODULE_SCOPE BOOL (INSTAPI* SQLConfigDataSource)(HWND, WORD, LPCSTR, LPCSTR);


MODULE_SCOPE BOOL (INSTAPI* SQLInstallerError)(WORD, DWORD*, LPSTR, WORD,
					       WORD*);

/*
 * Function that initialises the stubs
 */

Changes to generic/tdbcodbc.c.
53
54
55
56
57
58
59



60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
#	define TCL_UNUSED(T) T
#   elif defined(__GNUC__) && (__GNUC__ > 2)
#	define TCL_UNUSED(T) T JOIN(dummy, __LINE__) __attribute__((unused))
#   else
#	define TCL_UNUSED(T) T JOIN(dummy, __LINE__)
#   endif
#endif




/* Static data contained in this file */

TCL_DECLARE_MUTEX(hEnvMutex);	/* Mutex protecting the environment handle
				 * and its reference count */

static Tcl_LoadHandle odbcLoadHandle = NULL;
				/* Handle to the ODBC client library */
static Tcl_LoadHandle odbcInstLoadHandle = NULL;
				/* Handle to the ODBC installer library */
static SQLHENV hEnv = SQL_NULL_HENV;
				/* Handle to the global ODBC environment */
static size_t hEnvRefCount = 0;	/* Reference count on the global environment */
static Tcl_Size sizeofSQLWCHAR = sizeof(SQLWCHAR);
				/* Preset, will be autodetected later */

/*
 * Objects to create within the literal pool
 */

static const char* const LiteralValues[] = {







>
>
>










|


|







53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
#	define TCL_UNUSED(T) T
#   elif defined(__GNUC__) && (__GNUC__ > 2)
#	define TCL_UNUSED(T) T JOIN(dummy, __LINE__) __attribute__((unused))
#   else
#	define TCL_UNUSED(T) T JOIN(dummy, __LINE__)
#   endif
#endif
# ifndef TCL_SIZE_MODIFIER
#   define TCL_SIZE_MODIFIER ""
#endif

/* Static data contained in this file */

TCL_DECLARE_MUTEX(hEnvMutex);	/* Mutex protecting the environment handle
				 * and its reference count */

static Tcl_LoadHandle odbcLoadHandle = NULL;
				/* Handle to the ODBC client library */
static Tcl_LoadHandle odbcInstLoadHandle = NULL;
				/* Handle to the ODBC installer library */
static SQLHENV hStaticEnv = SQL_NULL_HENV;
				/* Handle to the global ODBC environment */
static size_t hEnvRefCount = 0;	/* Reference count on the global environment */
static size_t sizeofSQLWCHAR = sizeof(SQLWCHAR);
				/* Preset, will be autodetected later */

/*
 * Objects to create within the literal pool
 */

static const char* const LiteralValues[] = {
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
	    DeletePerInterpData(_pidata);	\
	}					\
    } while(0)

/*
 * Structure that carries the data for an ODBC connection
 *
 * 	The ConnectionData structure is refcounted to simplify the
 *	destruction of statements associated with a connection.
 *	When a connection is destroyed, the subordinate namespace that
 *	contains its statements is taken down, destroying them. It's
 *	not safe to take down the ConnectionData until nothing is
 *	referring to it, which avoids taking down the hDBC until the
 *	other objects that refer to it vanish.
 */







|







132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
	    DeletePerInterpData(_pidata);	\
	}					\
    } while(0)

/*
 * Structure that carries the data for an ODBC connection
 *
 *	The ConnectionData structure is refcounted to simplify the
 *	destruction of statements associated with a connection.
 *	When a connection is destroyed, the subordinate namespace that
 *	contains its statements is taken down, destroying them. It's
 *	not safe to take down the ConnectionData until nothing is
 *	referring to it, which avoids taking down the hDBC until the
 *	other objects that refer to it vanish.
 */
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
    } while(0)

/*
 * Structure that carries the data for an ODBC prepared statement.
 *
 *	Just as with connections, statements need to defer taking down
 *	their client data until other objects (i.e., result sets) that
 * 	refer to them have had a chance to clean up. Hence, this
 *	structure is reference counted as well.
 */

typedef struct StatementData {
    size_t refCount;		/* Reference count */
    Tcl_Object connectionObject;
				/* The connection object */







|







183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
    } while(0)

/*
 * Structure that carries the data for an ODBC prepared statement.
 *
 *	Just as with connections, statements need to defer taking down
 *	their client data until other objects (i.e., result sets) that
 *	refer to them have had a chance to clean up. Hence, this
 *	structure is reference counted as well.
 */

typedef struct StatementData {
    size_t refCount;		/* Reference count */
    Tcl_Object connectionObject;
				/* The connection object */
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
    Tcl_Size nativeSqlLen;		/* Length of the statement */
    SQLWCHAR* nativeMatchPatternW;
				/* Match pattern for metadata queries */
    Tcl_Size nativeMatchPatLen;	/* Length of the match pattern */
    struct ParamData* params;	/* Pointer to an array of ParamData
				 * structures that describe the data types
				 * of substituted parameters. */
    int typeNum;		/* Type number for a query of data types */
    int flags;			/* Flags tracking the state of the
				 * StatementData */
} StatementData;
#define IncrStatementRefCount(x)		\
    do {					\
	++((x)->refCount);			\
    } while (0)







|







205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
    Tcl_Size nativeSqlLen;		/* Length of the statement */
    SQLWCHAR* nativeMatchPatternW;
				/* Match pattern for metadata queries */
    Tcl_Size nativeMatchPatLen;	/* Length of the match pattern */
    struct ParamData* params;	/* Pointer to an array of ParamData
				 * structures that describe the data types
				 * of substituted parameters. */
    SQLSMALLINT typeNum;	/* Type number for a query of data types */
    int flags;			/* Flags tracking the state of the
				 * StatementData */
} StatementData;
#define IncrStatementRefCount(x)		\
    do {					\
	++((x)->refCount);			\
    } while (0)
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
    SQLULEN precision;		/* Size of the expected data */
    SQLSMALLINT scale;		/* Digits after decimal point of the
				 * expected data */
    SQLSMALLINT nullable;	/* Flag == 1 if the parameter is nullable */
} ParamData;

#define PARAM_KNOWN	1<<0	/* Something is known about the parameter */
#define PARAM_IN 	1<<1	/* Parameter is an input parameter */
#define PARAM_OUT 	1<<2	/* Parameter is an output parameter */
				/* (Both bits are set if parameter is
				 * an INOUT parameter) */

/*
 * Structure describing an ODBC result set.  The object that the Tcl
 * API terms a "result set" actually has to be represented by an ODBC
 * "statement", since an ODBC statement can have only one set of results







|
|







275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
    SQLULEN precision;		/* Size of the expected data */
    SQLSMALLINT scale;		/* Digits after decimal point of the
				 * expected data */
    SQLSMALLINT nullable;	/* Flag == 1 if the parameter is nullable */
} ParamData;

#define PARAM_KNOWN	1<<0	/* Something is known about the parameter */
#define PARAM_IN	1<<1	/* Parameter is an input parameter */
#define PARAM_OUT	1<<2	/* Parameter is an output parameter */
				/* (Both bits are set if parameter is
				 * an INOUT parameter) */

/*
 * Structure describing an ODBC result set.  The object that the Tcl
 * API terms a "result set" actually has to be represented by an ODBC
 * "statement", since an ODBC statement can have only one set of results
872
873
874
875
876
877
878

879
880
881
882
883
884
885
886
887
888
 */

static SQLWCHAR*
GetWCharStringFromObj(
    Tcl_Obj* obj,		/* Tcl object whose string rep is desired */
    Tcl_Size* lengthPtr		/* Length of the string */
) {

    char* bytes = Tcl_GetString(obj);
				/* UTF-8 representation of the input string */
    Tcl_Size len = obj->length;	/* Length of the input string in bytes */
    char* end = bytes + len;	/* End of UTF-8 representation */
    SQLWCHAR* retval;		/* Buffer to hold the converted string */
    SQLWCHAR* wcPtr;
    int shrink = 0;
    Tcl_UniChar ch = 0;

    len = (len + 1) * sizeofSQLWCHAR;







>
|

<







875
876
877
878
879
880
881
882
883
884

885
886
887
888
889
890
891
 */

static SQLWCHAR*
GetWCharStringFromObj(
    Tcl_Obj* obj,		/* Tcl object whose string rep is desired */
    Tcl_Size* lengthPtr		/* Length of the string */
) {
    Tcl_Size len;	/* Length of the input string in bytes */
    char* bytes = Tcl_GetStringFromObj(obj, &len);
				/* UTF-8 representation of the input string */

    char* end = bytes + len;	/* End of UTF-8 representation */
    SQLWCHAR* retval;		/* Buffer to hold the converted string */
    SQLWCHAR* wcPtr;
    int shrink = 0;
    Tcl_UniChar ch = 0;

    len = (len + 1) * sizeofSQLWCHAR;
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
	    if ((sizeof(Tcl_UniChar) > 2) && (uch > 0xffff)) {
		*ptr16++ = (((uch - 0x10000) >> 10) & 0x3ff) | 0xd800;
		uch = ((uch - 0x10000) & 0x3ff) | 0xdc00;
	    }
	    if (uch > 0x7f) {
		shrink = 1;
	    }
	    *ptr16++ = uch;
	}
	*ptr16 = 0;
	len = ptr16 - (unsigned short*) retval;
	wcPtr = (SQLWCHAR*) ptr16;
    } else {
	int *ptr32 = (int*) wcPtr;








|







910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
	    if ((sizeof(Tcl_UniChar) > 2) && (uch > 0xffff)) {
		*ptr16++ = (((uch - 0x10000) >> 10) & 0x3ff) | 0xd800;
		uch = ((uch - 0x10000) & 0x3ff) | 0xdc00;
	    }
	    if (uch > 0x7f) {
		shrink = 1;
	    }
	    *ptr16++ = (unsigned short)uch;
	}
	*ptr16 = 0;
	len = ptr16 - (unsigned short*) retval;
	wcPtr = (SQLWCHAR*) ptr16;
    } else {
	int *ptr32 = (int*) wcPtr;

1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
 * (Option Value Changed).
 *
 *-----------------------------------------------------------------------------
 */

static int
SQLStateIs(
    SQLSMALLINT handleType, 	/* Type of handle reporting the state */
    SQLHANDLE handle,		/* Handle that reported the state */
    const char* sqlstate	/* State to look for */
) {
    SQLCHAR state[6];		/* SQL state code from the diagnostic record */
    SQLSMALLINT stateLen;	/* String length of the state code */
    SQLSMALLINT i;		/* Loop index */
    SQLRETURN rc;		/* SQL result */







|







1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
 * (Option Value Changed).
 *
 *-----------------------------------------------------------------------------
 */

static int
SQLStateIs(
    SQLSMALLINT handleType,	/* Type of handle reporting the state */
    SQLHANDLE handle,		/* Handle that reported the state */
    const char* sqlstate	/* State to look for */
) {
    SQLCHAR state[6];		/* SQL state code from the diagnostic record */
    SQLSMALLINT stateLen;	/* String length of the state code */
    SQLSMALLINT i;		/* Loop index */
    SQLRETURN rc;		/* SQL result */
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
 *	Returns a Tcl_Obj with the human-readable level.
 *
 *-----------------------------------------------------------------------------
 */

static Tcl_Obj*
TranslateOdbcIsolationLevel(
    SQLINTEGER level, 		/* Isolation level */
    Tcl_Obj* literals[]		/* Pointer to the literal pool */
) {
    if (level & SQL_TXN_SERIALIZABLE) {
	return literals[LIT_SERIALIZABLE];
    }
    if (level & SQL_TXN_REPEATABLE_READ) {
	return literals[LIT_REPEATABLEREAD];







|







1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
 *	Returns a Tcl_Obj with the human-readable level.
 *
 *-----------------------------------------------------------------------------
 */

static Tcl_Obj*
TranslateOdbcIsolationLevel(
    SQLINTEGER level,		/* Isolation level */
    Tcl_Obj* literals[]		/* Pointer to the literal pool */
) {
    if (level & SQL_TXN_SERIALIZABLE) {
	return literals[LIT_SERIALIZABLE];
    }
    if (level & SQL_TXN_REPEATABLE_READ) {
	return literals[LIT_REPEATABLEREAD];
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
	    == NULL) {
	    Tcl_MutexUnlock(&hEnvMutex);
	    return SQL_NULL_HENV;
	}
	/*
	 * Allocate the ODBC environment
	 */
	rc = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &hEnv);
	if (SQL_SUCCEEDED(rc)) {
	    rc = SQLSetEnvAttr(hEnv, SQL_ATTR_ODBC_VERSION,
			       (SQLPOINTER) SQL_OV_ODBC3, 0);
	}
	if (!SQL_SUCCEEDED(rc)) {
	    /*
	     * The call failed. Report the error.
	     */
	    if (hEnv != SQL_NULL_HENV) {
		if (interp != NULL) {
		    TransferSQLError(interp, SQL_HANDLE_ENV, hEnv,
				     "(allocating environment handle)");
		}
		SQLFreeHandle(SQL_HANDLE_ENV, hEnv);
		hEnv = SQL_NULL_HENV;
	    } else {
		Tcl_SetObjResult(interp,
				 Tcl_NewStringObj("Could not allocate the "
						  "ODBC SQL environment.", -1));
		Tcl_SetErrorCode(interp, "TDBC", "GENERAL_ERROR",
				 "HY001", "ODBC", "-1", NULL);
	    }
	} else {
	    /*
	     * Detect real size of SQLWCHAR used by the driver manager.
	     */
	    SQLHDBC hDBC = SQL_NULL_HDBC;

	    sizeofSQLWCHAR = sizeof(SQLWCHAR);		/* fallback */
	    rc = SQLAllocHandle(SQL_HANDLE_DBC, hEnv, &hDBC);
	    if (SQL_SUCCEEDED(rc)) {
		SQLSMALLINT i, infoLen;
		char info[64];

		rc = SQLGetInfoW(hDBC, SQL_ODBC_VER, (SQLPOINTER) info,
				 sizeof(info), &infoLen);
		if (SQL_SUCCEEDED(rc) && infoLen >= 8) {







|

|






|

|


|
|














|







1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
	    == NULL) {
	    Tcl_MutexUnlock(&hEnvMutex);
	    return SQL_NULL_HENV;
	}
	/*
	 * Allocate the ODBC environment
	 */
	rc = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &hStaticEnv);
	if (SQL_SUCCEEDED(rc)) {
	    rc = SQLSetEnvAttr(hStaticEnv, SQL_ATTR_ODBC_VERSION,
			       (SQLPOINTER) SQL_OV_ODBC3, 0);
	}
	if (!SQL_SUCCEEDED(rc)) {
	    /*
	     * The call failed. Report the error.
	     */
	    if (hStaticEnv != SQL_NULL_HENV) {
		if (interp != NULL) {
		    TransferSQLError(interp, SQL_HANDLE_ENV, hStaticEnv,
				     "(allocating environment handle)");
		}
		SQLFreeHandle(SQL_HANDLE_ENV, hStaticEnv);
		hStaticEnv = SQL_NULL_HENV;
	    } else {
		Tcl_SetObjResult(interp,
				 Tcl_NewStringObj("Could not allocate the "
						  "ODBC SQL environment.", -1));
		Tcl_SetErrorCode(interp, "TDBC", "GENERAL_ERROR",
				 "HY001", "ODBC", "-1", NULL);
	    }
	} else {
	    /*
	     * Detect real size of SQLWCHAR used by the driver manager.
	     */
	    SQLHDBC hDBC = SQL_NULL_HDBC;

	    sizeofSQLWCHAR = sizeof(SQLWCHAR);		/* fallback */
	    rc = SQLAllocHandle(SQL_HANDLE_DBC, hStaticEnv, &hDBC);
	    if (SQL_SUCCEEDED(rc)) {
		SQLSMALLINT i, infoLen;
		char info[64];

		rc = SQLGetInfoW(hDBC, SQL_ODBC_VER, (SQLPOINTER) info,
				 sizeof(info), &infoLen);
		if (SQL_SUCCEEDED(rc) && infoLen >= 8) {
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
		SQLFreeHandle(SQL_HANDLE_DBC, hDBC);
	    }
	}
    }
    /*
     * On subsequent calls, simply adjust the refcount
     */
    if (hEnv != SQL_NULL_HENV) {
	++hEnvRefCount;
    }
    Tcl_MutexUnlock(&hEnvMutex);
    return hEnv;
}

/*
 *-----------------------------------------------------------------------------
 *
 * DismissHEnv --
 *







|



|







1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
		SQLFreeHandle(SQL_HANDLE_DBC, hDBC);
	    }
	}
    }
    /*
     * On subsequent calls, simply adjust the refcount
     */
    if (hStaticEnv != SQL_NULL_HENV) {
	++hEnvRefCount;
    }
    Tcl_MutexUnlock(&hEnvMutex);
    return hStaticEnv;
}

/*
 *-----------------------------------------------------------------------------
 *
 * DismissHEnv --
 *
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
 */

static void
DismissHEnv(void)
{
    Tcl_MutexLock(&hEnvMutex);
    if (hEnvRefCount-- <= 1) {
	SQLFreeHandle(SQL_HANDLE_ENV, hEnv);
	hEnv = SQL_NULL_HANDLE;
	if (odbcInstLoadHandle != NULL) {
	    Tcl_FSUnloadFile(NULL, odbcInstLoadHandle);
	    odbcInstLoadHandle = NULL;
	}
	Tcl_FSUnloadFile(NULL, odbcLoadHandle);
	odbcLoadHandle = NULL;
    }







|
|







1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
 */

static void
DismissHEnv(void)
{
    Tcl_MutexLock(&hEnvMutex);
    if (hEnvRefCount-- <= 1) {
	SQLFreeHandle(SQL_HANDLE_ENV, hStaticEnv);
	hStaticEnv = SQL_NULL_HANDLE;
	if (odbcInstLoadHandle != NULL) {
	    Tcl_FSUnloadFile(NULL, odbcInstLoadHandle);
	    odbcInstLoadHandle = NULL;
	}
	Tcl_FSUnloadFile(NULL, odbcLoadHandle);
	odbcLoadHandle = NULL;
    }
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
    Tcl_DString colNameDS;	/* Name of the current column, translated */
    Tcl_Obj* colNameObj;	/* Name of the current column, packaged in
				 * a Tcl_Obj */
    Tcl_HashTable nameHash;	/* Hash table to manage column name
				 * uniqueness. */
    Tcl_HashEntry* nameEntry;	/* Hash table entry for the current name */
    int isNew;			/* Flag that column name is unique */
    int count;			/* Count to append to the name */
    char numbuf[16];		/* Buffer to hold the appended count */
    SQLSMALLINT i;
    int retry;
    int status = TCL_ERROR;

    /* Create a hash table to manage column name uniqueness */

    Tcl_InitHashTable(&nameHash, TCL_STRING_KEYS);







|
|







1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
    Tcl_DString colNameDS;	/* Name of the current column, translated */
    Tcl_Obj* colNameObj;	/* Name of the current column, packaged in
				 * a Tcl_Obj */
    Tcl_HashTable nameHash;	/* Hash table to manage column name
				 * uniqueness. */
    Tcl_HashEntry* nameEntry;	/* Hash table entry for the current name */
    int isNew;			/* Flag that column name is unique */
    Tcl_Size count;			/* Count to append to the name */
    char numbuf[TCL_INTEGER_SPACE];		/* Buffer to hold the appended count */
    SQLSMALLINT i;
    int retry;
    int status = TCL_ERROR;

    /* Create a hash table to manage column name uniqueness */

    Tcl_InitHashTable(&nameHash, TCL_STRING_KEYS);
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
	rdata->results = (ParamData*) ckalloc(nColumns * sizeof(ParamData));
	for (i = 0; i < nColumns; ++i) {
	    retry = 0;
	    do {

		/* Describe one column of the result set */

		rc = SQLDescribeColW(hStmt, i + 1, colNameW,
				     colNameAllocLen, &colNameLen,
				     &(rdata->results[i].dataType),
				     &(rdata->results[i].precision),
				     &(rdata->results[i].scale),
				     &(rdata->results[i].nullable));

		/*
		 * Reallocate the name buffer and retry if the buffer was
		 * too small.
		 */

		if (colNameLen < colNameAllocLen) {
		    retry = 0;
		} else {
		    colNameAllocLen = 2 * colNameLen + 1;
		    if (colNameW != colNameBuf) {
			ckfree((char*) colNameW);
		    }
		    colNameW = (SQLWCHAR*)
			ckalloc(colNameAllocLen * sizeofSQLWCHAR);
		    retry = 1;
		}







|














|







1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
	rdata->results = (ParamData*) ckalloc(nColumns * sizeof(ParamData));
	for (i = 0; i < nColumns; ++i) {
	    retry = 0;
	    do {

		/* Describe one column of the result set */

		rc = SQLDescribeColW(hStmt, (SQLUSMALLINT)(i + 1), colNameW,
				     colNameAllocLen, &colNameLen,
				     &(rdata->results[i].dataType),
				     &(rdata->results[i].precision),
				     &(rdata->results[i].scale),
				     &(rdata->results[i].nullable));

		/*
		 * Reallocate the name buffer and retry if the buffer was
		 * too small.
		 */

		if (colNameLen < colNameAllocLen) {
		    retry = 0;
		} else {
		    colNameAllocLen = (SQLSMALLINT)(2 * colNameLen + 1);
		    if (colNameW != colNameBuf) {
			ckfree((char*) colNameW);
		    }
		    colNameW = (SQLWCHAR*)
			ckalloc(colNameAllocLen * sizeofSQLWCHAR);
		    retry = 1;
		}
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
		 * Non-unique name - append a # and the number of times
		 * we've seen it before.
		 */

		count = PTR2INT(Tcl_GetHashValue(nameEntry));
		++count;
		Tcl_SetHashValue(nameEntry, INT2PTR(count));
		snprintf(numbuf, sizeof(numbuf), "#%d", count);
		Tcl_AppendToObj(colNameObj, numbuf, -1);
	    }

	    /* Add column name to the list of column names */

	    Tcl_ListObjAppendElement(NULL, colNames, colNameObj);
	    Tcl_DStringFree(&colNameDS);







|







1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
		 * Non-unique name - append a # and the number of times
		 * we've seen it before.
		 */

		count = PTR2INT(Tcl_GetHashValue(nameEntry));
		++count;
		Tcl_SetHashValue(nameEntry, INT2PTR(count));
		snprintf(numbuf, sizeof(numbuf), "#%" TCL_SIZE_MODIFIER "d", count);
		Tcl_AppendToObj(colNameObj, numbuf, -1);
	    }

	    /* Add column name to the list of column names */

	    Tcl_ListObjAppendElement(NULL, colNames, colNameObj);
	    Tcl_DStringFree(&colNameDS);
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194

/*
 *-----------------------------------------------------------------------------
 *
 * ConnectionEndXcnMethod --
 *
 *	Method that requests that a pending transaction against a database
 * 	be committed or rolled back.
 *
 * Usage:
 *	$connection commit
 * -or- $connection rollback
 *
 * Parameters:
 *	None.







|







2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197

/*
 *-----------------------------------------------------------------------------
 *
 * ConnectionEndXcnMethod --
 *
 *	Method that requests that a pending transaction against a database
 *	be committed or rolled back.
 *
 * Usage:
 *	$connection commit
 * -or- $connection rollback
 *
 * Parameters:
 *	None.
2430
2431
2432
2433
2434
2435
2436
2437
2438
2439
2440
2441
2442
2443
2444
 *	refcounts accurate
 *
 *-----------------------------------------------------------------------------
 */

static int
CloneCmd(
    Tcl_Interp* dummy,		/* Tcl interpreter */
    TCL_UNUSED(void *),		/* Environment handle to be discarded */
    void **newClientData	/* New environment handle to be used */
) {
    *newClientData = GetHEnv(NULL);
    return TCL_OK;
}








|







2433
2434
2435
2436
2437
2438
2439
2440
2441
2442
2443
2444
2445
2446
2447
 *	refcounts accurate
 *
 *-----------------------------------------------------------------------------
 */

static int
CloneCmd(
    TCL_UNUSED(Tcl_Interp *), /* Tcl interpreter */
    TCL_UNUSED(void *),		/* Environment handle to be discarded */
    void **newClientData	/* New environment handle to be used */
) {
    *newClientData = GetHEnv(NULL);
    return TCL_OK;
}

2574
2575
2576
2577
2578
2579
2580
2581
2582
2583
2584
2585
2586
2587
2588
 */

static int
StatementConstructor(
    TCL_UNUSED(void *),		/* Not used */
    Tcl_Interp* interp,		/* Tcl interpreter */
    Tcl_ObjectContext context,	/* Object context  */
    int objc, 			/* Parameter count */
    Tcl_Obj *const objv[]	/* Parameter vector */
) {
    Tcl_Object thisObject = Tcl_ObjectContextObject(context);
				/* The current statement object */
    Tcl_Size skip = Tcl_ObjectContextSkippedArgs(context);
				/* The number of args to skip */
    Tcl_Object connectionObject;







|







2577
2578
2579
2580
2581
2582
2583
2584
2585
2586
2587
2588
2589
2590
2591
 */

static int
StatementConstructor(
    TCL_UNUSED(void *),		/* Not used */
    Tcl_Interp* interp,		/* Tcl interpreter */
    Tcl_ObjectContext context,	/* Object context  */
    int objc,			/* Parameter count */
    Tcl_Obj *const objv[]	/* Parameter vector */
) {
    Tcl_Object thisObject = Tcl_ObjectContextObject(context);
				/* The current statement object */
    Tcl_Size skip = Tcl_ObjectContextSkippedArgs(context);
				/* The number of args to skip */
    Tcl_Object connectionObject;
2640
2641
2642
2643
2644
2645
2646
2647
2648
2649
2650
2651
2652
2653
2654
2655
    if (Tcl_ListObjGetElements(interp, tokens, &tokenc, &tokenv) != TCL_OK) {
	Tcl_DecrRefCount(tokens);
	goto freeSData;
    }
    nativeSql = Tcl_NewObj();
    Tcl_IncrRefCount(nativeSql);
    for (i = 0; i < tokenc; ++i) {
	tokenStr = Tcl_GetString(tokenv[i]);
	tokenLen = tokenv[i]->length;

	switch (tokenStr[0]) {
	case '$':
	case ':':
	    Tcl_AppendToObj(nativeSql, "?", 1);
	    Tcl_ListObjAppendElement(NULL, sdata->subVars,
				     Tcl_NewStringObj(tokenStr+1, tokenLen-1));







|
<







2643
2644
2645
2646
2647
2648
2649
2650

2651
2652
2653
2654
2655
2656
2657
    if (Tcl_ListObjGetElements(interp, tokens, &tokenc, &tokenv) != TCL_OK) {
	Tcl_DecrRefCount(tokens);
	goto freeSData;
    }
    nativeSql = Tcl_NewObj();
    Tcl_IncrRefCount(nativeSql);
    for (i = 0; i < tokenc; ++i) {
	tokenStr = Tcl_GetStringFromObj(tokenv[i], &tokenLen);


	switch (tokenStr[0]) {
	case '$':
	case ':':
	    Tcl_AppendToObj(nativeSql, "?", 1);
	    Tcl_ListObjAppendElement(NULL, sdata->subVars,
				     Tcl_NewStringObj(tokenStr+1, tokenLen-1));
2709
2710
2711
2712
2713
2714
2715
2716
2717
2718
2719
2720
2721
2722
2723

	/*
	 * Try to describe the parameters for the sake of consistency
	 * in conversion and efficiency in execution.
	 */

	for (i = 0; i < nParams; ++i) {
	    rc = SQLDescribeParam(sdata->hStmt, i+1,
				  &(sdata->params[i].dataType),
				  &(sdata->params[i].precision),
				  &(sdata->params[i].scale),
				  &(sdata->params[i].nullable));
	    if (SQL_SUCCEEDED(rc)) {
		/*
		 * FIXME: SQLDescribeParam doesn't actually describe







|







2711
2712
2713
2714
2715
2716
2717
2718
2719
2720
2721
2722
2723
2724
2725

	/*
	 * Try to describe the parameters for the sake of consistency
	 * in conversion and efficiency in execution.
	 */

	for (i = 0; i < nParams; ++i) {
	    rc = SQLDescribeParam(sdata->hStmt, (SQLUSMALLINT)(i+1),
				  &(sdata->params[i].dataType),
				  &(sdata->params[i].precision),
				  &(sdata->params[i].scale),
				  &(sdata->params[i].nullable));
	    if (SQL_SUCCEEDED(rc)) {
		/*
		 * FIXME: SQLDescribeParam doesn't actually describe
2779
2780
2781
2782
2783
2784
2785
2786
2787
2788
2789
2790
2791
2792
2793
 */

static int
StatementConnectionMethod(
    TCL_UNUSED(void *),		/* Not used */
    Tcl_Interp* interp,		/* Tcl interpreter */
    Tcl_ObjectContext context,	/* Object context  */
    TCL_UNUSED(int), 			/* Parameter count */
    TCL_UNUSED(Tcl_Obj *const *)/* Parameter vector */
) {
    Tcl_Object thisObject = Tcl_ObjectContextObject(context);
				/* The current statement object */
    StatementData* sdata;	/* The current statement */
    Tcl_Object connectionObject;
				/* The object representing the connection */







|







2781
2782
2783
2784
2785
2786
2787
2788
2789
2790
2791
2792
2793
2794
2795
 */

static int
StatementConnectionMethod(
    TCL_UNUSED(void *),		/* Not used */
    Tcl_Interp* interp,		/* Tcl interpreter */
    Tcl_ObjectContext context,	/* Object context  */
    TCL_UNUSED(int),			/* Parameter count */
    TCL_UNUSED(Tcl_Obj *const *)/* Parameter vector */
) {
    Tcl_Object thisObject = Tcl_ObjectContextObject(context);
				/* The current statement object */
    StatementData* sdata;	/* The current statement */
    Tcl_Object connectionObject;
				/* The object representing the connection */
2823
2824
2825
2826
2827
2828
2829
2830
2831
2832
2833
2834
2835
2836
2837
 */

static int
StatementParamListMethod(
    TCL_UNUSED(void *),		/* Not used */
    Tcl_Interp* interp,		/* Tcl interpreter */
    Tcl_ObjectContext context,	/* Object context  */
    TCL_UNUSED(int), 			/* Parameter count */
    TCL_UNUSED(Tcl_Obj *const *)	/* Parameter vector */
) {
    Tcl_Object thisObject = Tcl_ObjectContextObject(context);
				/* The current statement object */
    StatementData* sdata;	/* The current statement */
    Tcl_Obj **paramNames;	/* Parameter list to the current statement */
    Tcl_Size nParams;	/* Parameter count for the current statement */







|







2825
2826
2827
2828
2829
2830
2831
2832
2833
2834
2835
2836
2837
2838
2839
 */

static int
StatementParamListMethod(
    TCL_UNUSED(void *),		/* Not used */
    Tcl_Interp* interp,		/* Tcl interpreter */
    Tcl_ObjectContext context,	/* Object context  */
    TCL_UNUSED(int),			/* Parameter count */
    TCL_UNUSED(Tcl_Obj *const *)	/* Parameter vector */
) {
    Tcl_Object thisObject = Tcl_ObjectContextObject(context);
				/* The current statement object */
    StatementData* sdata;	/* The current statement */
    Tcl_Obj **paramNames;	/* Parameter list to the current statement */
    Tcl_Size nParams;	/* Parameter count for the current statement */
2879
2880
2881
2882
2883
2884
2885
2886
2887
2888
2889
2890
2891
2892
2893
 */

static int
StatementParamtypeMethod(
    TCL_UNUSED(void *),		/* Not used */
    Tcl_Interp* interp,		/* Tcl interpreter */
    Tcl_ObjectContext context,	/* Object context  */
    int objc, 			/* Parameter count */
    Tcl_Obj *const objv[]	/* Parameter vector */
) {
    Tcl_Object thisObject = Tcl_ObjectContextObject(context);
				/* The current statement object */
    StatementData* sdata;	/* The current statement */
    int matchCount = 0;		/* The number of variables in the given
				 * statement that match the given one */







|







2881
2882
2883
2884
2885
2886
2887
2888
2889
2890
2891
2892
2893
2894
2895
 */

static int
StatementParamtypeMethod(
    TCL_UNUSED(void *),		/* Not used */
    Tcl_Interp* interp,		/* Tcl interpreter */
    Tcl_ObjectContext context,	/* Object context  */
    int objc,			/* Parameter count */
    Tcl_Obj *const objv[]	/* Parameter vector */
) {
    Tcl_Object thisObject = Tcl_ObjectContextObject(context);
				/* The current statement object */
    StatementData* sdata;	/* The current statement */
    int matchCount = 0;		/* The number of variables in the given
				 * statement that match the given one */
2950
2951
2952
2953
2954
2955
2956
2957
2958
2959
2960
2961
2962
2963
2964
	targetName = Tcl_GetString(targetNameObj);
	if (!strcmp(paramName, targetName)) {
	    ++matchCount;

	    sdata->params[i].flags = dir;
	    sdata->params[i].dataType = odbcType;
	    sdata->params[i].precision = precision;
	    sdata->params[i].scale = scale;
	    sdata->params[i].nullable = 1;
				/* TODO - Update TIP so that user
				 * can specify nullable? */
	}
    }
    if (matchCount == 0) {
	errorObj = Tcl_NewStringObj("unknown parameter \"", -1);







|







2952
2953
2954
2955
2956
2957
2958
2959
2960
2961
2962
2963
2964
2965
2966
	targetName = Tcl_GetString(targetNameObj);
	if (!strcmp(paramName, targetName)) {
	    ++matchCount;

	    sdata->params[i].flags = dir;
	    sdata->params[i].dataType = odbcType;
	    sdata->params[i].precision = precision;
	    sdata->params[i].scale = (SQLSMALLINT)scale;
	    sdata->params[i].nullable = 1;
				/* TODO - Update TIP so that user
				 * can specify nullable? */
	}
    }
    if (matchCount == 0) {
	errorObj = Tcl_NewStringObj("unknown parameter \"", -1);
3008
3009
3010
3011
3012
3013
3014
3015
3016
3017
3018
3019
3020
3021
3022
 */

static int
TablesStatementConstructor(
    TCL_UNUSED(void *),		/* Not used */
    Tcl_Interp* interp,		/* Tcl interpreter */
    Tcl_ObjectContext context,	/* Object context  */
    int objc, 			/* Parameter count */
    Tcl_Obj *const objv[]	/* Parameter vector */
) {

    Tcl_Object thisObject = Tcl_ObjectContextObject(context);
				/* The current statement object */
    Tcl_Size skip = Tcl_ObjectContextSkippedArgs(context);
				/* The number of initial args to this call */







|







3010
3011
3012
3013
3014
3015
3016
3017
3018
3019
3020
3021
3022
3023
3024
 */

static int
TablesStatementConstructor(
    TCL_UNUSED(void *),		/* Not used */
    Tcl_Interp* interp,		/* Tcl interpreter */
    Tcl_ObjectContext context,	/* Object context  */
    int objc,			/* Parameter count */
    Tcl_Obj *const objv[]	/* Parameter vector */
) {

    Tcl_Object thisObject = Tcl_ObjectContextObject(context);
				/* The current statement object */
    Tcl_Size skip = Tcl_ObjectContextSkippedArgs(context);
				/* The number of initial args to this call */
3108
3109
3110
3111
3112
3113
3114
3115
3116
3117
3118
3119
3120
3121
3122
 */

static int
ColumnsStatementConstructor(
    TCL_UNUSED(void *),		/* Not used */
    Tcl_Interp* interp,		/* Tcl interpreter */
    Tcl_ObjectContext context,	/* Object context  */
    int objc, 			/* Parameter count */
    Tcl_Obj *const objv[]	/* Parameter vector */
) {

    Tcl_Object thisObject = Tcl_ObjectContextObject(context);
				/* The current statement object */
    Tcl_Size skip = Tcl_ObjectContextSkippedArgs(context);
				/* The number of parameters to skip */







|







3110
3111
3112
3113
3114
3115
3116
3117
3118
3119
3120
3121
3122
3123
3124
 */

static int
ColumnsStatementConstructor(
    TCL_UNUSED(void *),		/* Not used */
    Tcl_Interp* interp,		/* Tcl interpreter */
    Tcl_ObjectContext context,	/* Object context  */
    int objc,			/* Parameter count */
    Tcl_Obj *const objv[]	/* Parameter vector */
) {

    Tcl_Object thisObject = Tcl_ObjectContextObject(context);
				/* The current statement object */
    Tcl_Size skip = Tcl_ObjectContextSkippedArgs(context);
				/* The number of parameters to skip */
3211
3212
3213
3214
3215
3216
3217
3218
3219
3220
3221
3222
3223
3224
3225
 */

static int
PrimarykeysStatementConstructor(
    TCL_UNUSED(void *),		/* Not used */
    Tcl_Interp* interp,		/* Tcl interpreter */
    Tcl_ObjectContext context,	/* Object context  */
    int objc, 			/* Parameter count */
    Tcl_Obj *const objv[]	/* Parameter vector */
) {

    Tcl_Object thisObject = Tcl_ObjectContextObject(context);
				/* The current statement object */
    Tcl_Size skip = Tcl_ObjectContextSkippedArgs(context);
				/* The number of parameters to skip */







|







3213
3214
3215
3216
3217
3218
3219
3220
3221
3222
3223
3224
3225
3226
3227
 */

static int
PrimarykeysStatementConstructor(
    TCL_UNUSED(void *),		/* Not used */
    Tcl_Interp* interp,		/* Tcl interpreter */
    Tcl_ObjectContext context,	/* Object context  */
    int objc,			/* Parameter count */
    Tcl_Obj *const objv[]	/* Parameter vector */
) {

    Tcl_Object thisObject = Tcl_ObjectContextObject(context);
				/* The current statement object */
    Tcl_Size skip = Tcl_ObjectContextSkippedArgs(context);
				/* The number of parameters to skip */
3313
3314
3315
3316
3317
3318
3319
3320
3321
3322
3323
3324
3325
3326
3327
 */

static int
ForeignkeysStatementConstructor(
    TCL_UNUSED(void *),		/* Not used */
    Tcl_Interp* interp,		/* Tcl interpreter */
    Tcl_ObjectContext context,	/* Object context  */
    int objc, 			/* Parameter count */
    Tcl_Obj *const objv[]	/* Parameter vector */
) {

    Tcl_Object thisObject = Tcl_ObjectContextObject(context);
				/* The current statement object */
    Tcl_Size skip = Tcl_ObjectContextSkippedArgs(context);
				/* The number of parameters to skip */







|







3315
3316
3317
3318
3319
3320
3321
3322
3323
3324
3325
3326
3327
3328
3329
 */

static int
ForeignkeysStatementConstructor(
    TCL_UNUSED(void *),		/* Not used */
    Tcl_Interp* interp,		/* Tcl interpreter */
    Tcl_ObjectContext context,	/* Object context  */
    int objc,			/* Parameter count */
    Tcl_Obj *const objv[]	/* Parameter vector */
) {

    Tcl_Object thisObject = Tcl_ObjectContextObject(context);
				/* The current statement object */
    Tcl_Size skip = Tcl_ObjectContextSkippedArgs(context);
				/* The number of parameters to skip */
3452
3453
3454
3455
3456
3457
3458
3459
3460
3461
3462
3463
3464
3465
3466
3467
3468
3469
 *	instance metadata.
 *
 *-----------------------------------------------------------------------------
 */

static int
EvaldirectStatementConstructor(
    void *clientData,	/* Not used */
    Tcl_Interp* interp,		/* Tcl interpreter */
    Tcl_ObjectContext context,	/* Object context  */
    int objc, 			/* Parameter count */
    Tcl_Obj *const objv[]	/* Parameter vector */
) {

    Tcl_Object thisObject = Tcl_ObjectContextObject(context);
				/* The current statement object */
    Tcl_Size skip = Tcl_ObjectContextSkippedArgs(context);
				/* The number of parameters to skip */







|


|







3454
3455
3456
3457
3458
3459
3460
3461
3462
3463
3464
3465
3466
3467
3468
3469
3470
3471
 *	instance metadata.
 *
 *-----------------------------------------------------------------------------
 */

static int
EvaldirectStatementConstructor(
    TCL_UNUSED(void *),
    Tcl_Interp* interp,		/* Tcl interpreter */
    Tcl_ObjectContext context,	/* Object context  */
    int objc,			/* Parameter count */
    Tcl_Obj *const objv[]	/* Parameter vector */
) {

    Tcl_Object thisObject = Tcl_ObjectContextObject(context);
				/* The current statement object */
    Tcl_Size skip = Tcl_ObjectContextSkippedArgs(context);
				/* The number of parameters to skip */
3563
3564
3565
3566
3567
3568
3569
3570
3571
3572
3573
3574
3575
3576
3577
 */

static int
TypesStatementConstructor(
    TCL_UNUSED(void *),		/* Not used */
    Tcl_Interp* interp,		/* Tcl interpreter */
    Tcl_ObjectContext context,	/* Object context  */
    int objc, 			/* Parameter count */
    Tcl_Obj *const objv[]	/* Parameter vector */
) {

    Tcl_Object thisObject = Tcl_ObjectContextObject(context);
				/* The current statement object */
    Tcl_Size skip = Tcl_ObjectContextSkippedArgs(context);
				/* The number of leading args to skip */







|







3565
3566
3567
3568
3569
3570
3571
3572
3573
3574
3575
3576
3577
3578
3579
 */

static int
TypesStatementConstructor(
    TCL_UNUSED(void *),		/* Not used */
    Tcl_Interp* interp,		/* Tcl interpreter */
    Tcl_ObjectContext context,	/* Object context  */
    int objc,			/* Parameter count */
    Tcl_Obj *const objv[]	/* Parameter vector */
) {

    Tcl_Object thisObject = Tcl_ObjectContextObject(context);
				/* The current statement object */
    Tcl_Size skip = Tcl_ObjectContextSkippedArgs(context);
				/* The number of leading args to skip */
3625
3626
3627
3628
3629
3630
3631
3632
3633
3634
3635
3636
3637
3638
3639
    }

    /*
     * Stash the type number in the statement data, and set a flag
     * that that's what we have there.
     */

    sdata->typeNum = typeNum;
    sdata->flags = STATEMENT_FLAG_TYPES;

    /* Attach the current statement data as metadata to the current object */


    Tcl_ObjectSetMetadata(thisObject, &statementDataType, sdata);
    return TCL_OK;







|







3627
3628
3629
3630
3631
3632
3633
3634
3635
3636
3637
3638
3639
3640
3641
    }

    /*
     * Stash the type number in the statement data, and set a flag
     * that that's what we have there.
     */

    sdata->typeNum = (SQLSMALLINT)typeNum;
    sdata->flags = STATEMENT_FLAG_TYPES;

    /* Attach the current statement data as metadata to the current object */


    Tcl_ObjectSetMetadata(thisObject, &statementDataType, sdata);
    return TCL_OK;
3739
3740
3741
3742
3743
3744
3745
3746
3747
3748
3749
3750
3751
3752
3753
 */

static int
ResultSetConstructor(
    TCL_UNUSED(void *),		/* Not used */
    Tcl_Interp* interp,		/* Tcl interpreter */
    Tcl_ObjectContext context,	/* Object context  */
    int objc, 			/* Parameter count */
    Tcl_Obj *const objv[]	/* Parameter vector */
) {

    Tcl_Object thisObject = Tcl_ObjectContextObject(context);
				/* The current result set object */
    Tcl_Size skip = Tcl_ObjectContextSkippedArgs(context);
				/* Number of skipped args in the







|







3741
3742
3743
3744
3745
3746
3747
3748
3749
3750
3751
3752
3753
3754
3755
 */

static int
ResultSetConstructor(
    TCL_UNUSED(void *),		/* Not used */
    Tcl_Interp* interp,		/* Tcl interpreter */
    Tcl_ObjectContext context,	/* Object context  */
    int objc,			/* Parameter count */
    Tcl_Obj *const objv[]	/* Parameter vector */
) {

    Tcl_Object thisObject = Tcl_ObjectContextObject(context);
				/* The current result set object */
    Tcl_Size skip = Tcl_ObjectContextSkippedArgs(context);
				/* Number of skipped args in the
4008
4009
4010
4011
4012
4013
4014
4015
4016
4017
4018
4019
4020
4021
4022
4023
		} else {

		    /*
		     * We need to convert the character string to system
		     * encoding and store in rdata->bindStrings[nBound].
		     */
		    dataType = SQL_C_CHAR;
		    paramVal = Tcl_GetString(paramValObj);
		    paramLen = paramValObj->length;
		    Tcl_DStringInit(&paramExternal);
		    (void)Tcl_UtfToExternalDString(NULL, paramVal, paramLen,
					     &paramExternal);
		    paramExternalLen = Tcl_DStringLength(&paramExternal);
		    rdata->bindStrings[nBound] = (SQLCHAR*)
			ckalloc(paramExternalLen + 1);
		    memcpy(rdata->bindStrings[nBound],







|
<







4010
4011
4012
4013
4014
4015
4016
4017

4018
4019
4020
4021
4022
4023
4024
		} else {

		    /*
		     * We need to convert the character string to system
		     * encoding and store in rdata->bindStrings[nBound].
		     */
		    dataType = SQL_C_CHAR;
		    paramVal = Tcl_GetStringFromObj(paramValObj, &paramLen);

		    Tcl_DStringInit(&paramExternal);
		    (void)Tcl_UtfToExternalDString(NULL, paramVal, paramLen,
					     &paramExternal);
		    paramExternalLen = Tcl_DStringLength(&paramExternal);
		    rdata->bindStrings[nBound] = (SQLCHAR*)
			ckalloc(paramExternalLen + 1);
		    memcpy(rdata->bindStrings[nBound],
4035
4036
4037
4038
4039
4040
4041
4042
4043
4044
4045
4046
4047
4048
4049

	    dataType = SQL_C_CHAR;
	    rdata->bindStrings[nBound] = NULL;
	    paramExternalLen = paramLen = 0;
	    rdata->bindStringLengths[nBound] = SQL_NULL_DATA;
	}
	rc = SQLBindParameter(rdata->hStmt,
			      nBound + 1,
			      SQL_PARAM_INPUT, /* TODO - Fix this! */
			      dataType,
			      sdata->params[nBound].dataType,
			      sdata->params[nBound].precision,
			      sdata->params[nBound].scale,
			      rdata->bindStrings[nBound],
			      paramExternalLen,







|







4036
4037
4038
4039
4040
4041
4042
4043
4044
4045
4046
4047
4048
4049
4050

	    dataType = SQL_C_CHAR;
	    rdata->bindStrings[nBound] = NULL;
	    paramExternalLen = paramLen = 0;
	    rdata->bindStringLengths[nBound] = SQL_NULL_DATA;
	}
	rc = SQLBindParameter(rdata->hStmt,
			      (SQLUSMALLINT)(nBound + 1),
			      SQL_PARAM_INPUT, /* TODO - Fix this! */
			      dataType,
			      sdata->params[nBound].dataType,
			      sdata->params[nBound].precision,
			      sdata->params[nBound].scale,
			      rdata->bindStrings[nBound],
			      paramExternalLen,
4188
4189
4190
4191
4192
4193
4194
4195
4196
4197
4198
4199
4200
4201
4202
 */

static int
ResultSetColumnsMethod(
    TCL_UNUSED(void *),		/* Not used */
    Tcl_Interp* interp,		/* Tcl interpreter */
    Tcl_ObjectContext context,	/* Object context  */
    int objc, 			/* Parameter count */
    Tcl_Obj *const objv[]	/* Parameter vector */
) {
    Tcl_Object thisObject = Tcl_ObjectContextObject(context);
				/* The current result set object */
    ResultSetData* rdata = (ResultSetData*)
	Tcl_ObjectGetMetadata(thisObject, &resultSetDataType);








|







4189
4190
4191
4192
4193
4194
4195
4196
4197
4198
4199
4200
4201
4202
4203
 */

static int
ResultSetColumnsMethod(
    TCL_UNUSED(void *),		/* Not used */
    Tcl_Interp* interp,		/* Tcl interpreter */
    Tcl_ObjectContext context,	/* Object context  */
    int objc,			/* Parameter count */
    Tcl_Obj *const objv[]	/* Parameter vector */
) {
    Tcl_Object thisObject = Tcl_ObjectContextObject(context);
				/* The current result set object */
    ResultSetData* rdata = (ResultSetData*)
	Tcl_ObjectGetMetadata(thisObject, &resultSetDataType);

4241
4242
4243
4244
4245
4246
4247
4248
4249
4250
4251
4252
4253
4254
4255
 */

static int
ResultSetNextresultsMethod(
    TCL_UNUSED(void *),		/* Not used */
    Tcl_Interp* interp,		/* Tcl interpreter */
    Tcl_ObjectContext context,	/* Object context  */
    TCL_UNUSED(int), 			/* Parameter count */
    TCL_UNUSED(Tcl_Obj *const *)	/* Parameter vector */
) {
    Tcl_Object thisObject = Tcl_ObjectContextObject(context);
				/* The current result set object */
    ResultSetData* rdata = (ResultSetData*)
	Tcl_ObjectGetMetadata(thisObject, &resultSetDataType);
				/* Data pertaining to the current result set */







|







4242
4243
4244
4245
4246
4247
4248
4249
4250
4251
4252
4253
4254
4255
4256
 */

static int
ResultSetNextresultsMethod(
    TCL_UNUSED(void *),		/* Not used */
    Tcl_Interp* interp,		/* Tcl interpreter */
    Tcl_ObjectContext context,	/* Object context  */
    TCL_UNUSED(int),			/* Parameter count */
    TCL_UNUSED(Tcl_Obj *const *)	/* Parameter vector */
) {
    Tcl_Object thisObject = Tcl_ObjectContextObject(context);
				/* The current result set object */
    ResultSetData* rdata = (ResultSetData*)
	Tcl_ObjectGetMetadata(thisObject, &resultSetDataType);
				/* Data pertaining to the current result set */
4329
4330
4331
4332
4333
4334
4335
4336
4337
4338
4339
4340
4341
4342
4343
4344
4345
4346
4347

static int
ResultSetNextrowMethod(
    void *clientData,	/* 1 if lists are to be returned, 0 if
				 * dicts are to be returned */
    Tcl_Interp* interp,		/* Tcl interpreter */
    Tcl_ObjectContext context,	/* Object context  */
    int objc, 			/* Parameter count */
    Tcl_Obj *const objv[]	/* Parameter vector */
) {

    int lists = PTR2INT(clientData);
				/* Flag == 1 if lists are to be returned,
				 * 0 if dicts are to be returned */

    Tcl_Object thisObject = Tcl_ObjectContextObject(context);
				/* The current result set object */
    ResultSetData* rdata = (ResultSetData*)
	Tcl_ObjectGetMetadata(thisObject, &resultSetDataType);







|



|







4330
4331
4332
4333
4334
4335
4336
4337
4338
4339
4340
4341
4342
4343
4344
4345
4346
4347
4348

static int
ResultSetNextrowMethod(
    void *clientData,	/* 1 if lists are to be returned, 0 if
				 * dicts are to be returned */
    Tcl_Interp* interp,		/* Tcl interpreter */
    Tcl_ObjectContext context,	/* Object context  */
    int objc,			/* Parameter count */
    Tcl_Obj *const objv[]	/* Parameter vector */
) {

    int lists = (int)PTR2INT(clientData);
				/* Flag == 1 if lists are to be returned,
				 * 0 if dicts are to be returned */

    Tcl_Object thisObject = Tcl_ObjectContextObject(context);
				/* The current result set object */
    ResultSetData* rdata = (ResultSetData*)
	Tcl_ObjectGetMetadata(thisObject, &resultSetDataType);
4522
4523
4524
4525
4526
4527
4528
4529
4530
4531
4532
4533
4534
4535
4536
4537
4538
4539
4540
4541
4542
4543
4544
4545
4546
4547
4548
4549
4550
4551
4552
4553
4554
4555
4556
	    goto convertUnknown;
	}

    case SQL_BIGINT:
    convertWide:
	/* A wide integer */
	colLen = sizeof(colWide); colWide = 0;
	rc = SQLGetData(rdata->hStmt, i+1, SQL_C_SBIGINT,
			(SQLPOINTER) &colWide, sizeof(colWide), &colLen);
	if (!SQL_SUCCEEDED(rc)) {
	    char info[80];
	    snprintf(info, sizeof(info), "(retrieving result set column #%d)\n", i+1);
	    TransferSQLError(interp, SQL_HANDLE_STMT, rdata->hStmt, info);
	    return TCL_ERROR;
	}
	if (colLen != SQL_NULL_DATA && colLen != SQL_NO_TOTAL) {
	    colObj = Tcl_NewWideIntObj((Tcl_WideInt)colWide);
	}
	break;

    case SQL_BIT:
    case SQL_INTEGER:
    case SQL_SMALLINT:
    case SQL_TINYINT:
    convertLong:
	/* An integer no larger than 'long' */
	colLen = sizeof(colLong.si); colLong.si = 0;
	rc = SQLGetData(rdata->hStmt, i+1, SQL_C_SLONG,
			(SQLPOINTER) &colLong.si, sizeof(colLong.si), &colLen);
	if (!SQL_SUCCEEDED(rc)) {
	    char info[80];
	    snprintf(info, sizeof(info), "(retrieving result set column #%d)\n", i+1);
	    TransferSQLError(interp, SQL_HANDLE_STMT, rdata->hStmt, info);
	    ckfree(info);
	    return TCL_ERROR;







|



















|







4523
4524
4525
4526
4527
4528
4529
4530
4531
4532
4533
4534
4535
4536
4537
4538
4539
4540
4541
4542
4543
4544
4545
4546
4547
4548
4549
4550
4551
4552
4553
4554
4555
4556
4557
	    goto convertUnknown;
	}

    case SQL_BIGINT:
    convertWide:
	/* A wide integer */
	colLen = sizeof(colWide); colWide = 0;
	rc = SQLGetData(rdata->hStmt, (SQLUSMALLINT)(i+1), SQL_C_SBIGINT,
			(SQLPOINTER) &colWide, sizeof(colWide), &colLen);
	if (!SQL_SUCCEEDED(rc)) {
	    char info[80];
	    snprintf(info, sizeof(info), "(retrieving result set column #%d)\n", i+1);
	    TransferSQLError(interp, SQL_HANDLE_STMT, rdata->hStmt, info);
	    return TCL_ERROR;
	}
	if (colLen != SQL_NULL_DATA && colLen != SQL_NO_TOTAL) {
	    colObj = Tcl_NewWideIntObj((Tcl_WideInt)colWide);
	}
	break;

    case SQL_BIT:
    case SQL_INTEGER:
    case SQL_SMALLINT:
    case SQL_TINYINT:
    convertLong:
	/* An integer no larger than 'long' */
	colLen = sizeof(colLong.si); colLong.si = 0;
	rc = SQLGetData(rdata->hStmt, (SQLUSMALLINT)(i+1), SQL_C_SLONG,
			(SQLPOINTER) &colLong.si, sizeof(colLong.si), &colLen);
	if (!SQL_SUCCEEDED(rc)) {
	    char info[80];
	    snprintf(info, sizeof(info), "(retrieving result set column #%d)\n", i+1);
	    TransferSQLError(interp, SQL_HANDLE_STMT, rdata->hStmt, info);
	    ckfree(info);
	    return TCL_ERROR;
4579
4580
4581
4582
4583
4584
4585
4586
4587
4588
4589
4590
4591
4592
4593
    case SQL_DOUBLE:
    convertDouble:
	/*
	 * A single- or double-precision floating point number.
	 * Reals are widened to doubles.
	 */
	colLen = sizeof(colDouble); colDouble = 0.0;
	rc = SQLGetData(rdata->hStmt, i+1, SQL_C_DOUBLE,
			(SQLPOINTER) &colDouble, sizeof(colDouble),
			&colLen);
	if (!SQL_SUCCEEDED(rc)) {
	    char info[80];
	    snprintf(info, sizeof(info), "(retrieving result set column #%d)\n", i+1);
	    TransferSQLError(interp, SQL_HANDLE_STMT, rdata->hStmt, info);
	    ckfree(info);







|







4580
4581
4582
4583
4584
4585
4586
4587
4588
4589
4590
4591
4592
4593
4594
    case SQL_DOUBLE:
    convertDouble:
	/*
	 * A single- or double-precision floating point number.
	 * Reals are widened to doubles.
	 */
	colLen = sizeof(colDouble); colDouble = 0.0;
	rc = SQLGetData(rdata->hStmt, (SQLUSMALLINT)(i+1), SQL_C_DOUBLE,
			(SQLPOINTER) &colDouble, sizeof(colDouble),
			&colLen);
	if (!SQL_SUCCEEDED(rc)) {
	    char info[80];
	    snprintf(info, sizeof(info), "(retrieving result set column #%d)\n", i+1);
	    TransferSQLError(interp, SQL_HANDLE_STMT, rdata->hStmt, info);
	    ckfree(info);
4636
4637
4638
4639
4640
4641
4642
4643
4644
4645
4646
4647
4648
4649
4650
	     * SQL_ERROR is returned. Store a background of zero so
	     * that it's always initialized.
	     */
	    colLen = 0;

	    /* Try to get the string */

	    rc = SQLGetData(rdata->hStmt, i+1, dataType,
			    (SQLPOINTER) (((char*)colPtr)+offset),
			    colAllocLen - offset,
			    &colLen);
	    if (rc == SQL_SUCCESS_WITH_INFO
		&& SQLStateIs(SQL_HANDLE_STMT, rdata->hStmt, "01004")) {
		/*
		 * The requested buffer was too small to hold the







|







4637
4638
4639
4640
4641
4642
4643
4644
4645
4646
4647
4648
4649
4650
4651
	     * SQL_ERROR is returned. Store a background of zero so
	     * that it's always initialized.
	     */
	    colLen = 0;

	    /* Try to get the string */

	    rc = SQLGetData(rdata->hStmt, (SQLUSMALLINT)(i+1), dataType,
			    (SQLPOINTER) (((char*)colPtr)+offset),
			    colAllocLen - offset,
			    &colLen);
	    if (rc == SQL_SUCCESS_WITH_INFO
		&& SQLStateIs(SQL_HANDLE_STMT, rdata->hStmt, "01004")) {
		/*
		 * The requested buffer was too small to hold the
4733
4734
4735
4736
4737
4738
4739
4740
4741
4742
4743
4744
4745
4746
4747
 */

static int
ResultSetRowcountMethod(
    TCL_UNUSED(void *),		/* Not used */
    Tcl_Interp* interp,		/* Tcl interpreter */
    Tcl_ObjectContext context,	/* Object context  */
    int objc, 			/* Parameter count */
    Tcl_Obj *const objv[]	/* Parameter vector */
) {
    Tcl_Object thisObject = Tcl_ObjectContextObject(context);
				/* The current result set object */
    ResultSetData* rdata = (ResultSetData*)
	Tcl_ObjectGetMetadata(thisObject, &resultSetDataType);
				/* Data pertaining to the current result set */







|







4734
4735
4736
4737
4738
4739
4740
4741
4742
4743
4744
4745
4746
4747
4748
 */

static int
ResultSetRowcountMethod(
    TCL_UNUSED(void *),		/* Not used */
    Tcl_Interp* interp,		/* Tcl interpreter */
    Tcl_ObjectContext context,	/* Object context  */
    int objc,			/* Parameter count */
    Tcl_Obj *const objv[]	/* Parameter vector */
) {
    Tcl_Object thisObject = Tcl_ObjectContextObject(context);
				/* The current result set object */
    ResultSetData* rdata = (ResultSetData*)
	Tcl_ObjectGetMetadata(thisObject, &resultSetDataType);
				/* Data pertaining to the current result set */
5210
5211
5212
5213
5214
5215
5216
5217
5218
5219
5220
5221
5222
5223
5224
	WORD value;
    } flags[] = {
	{ "add",		ODBC_ADD_DSN },
	{ "add_system",		ODBC_ADD_SYS_DSN },
	{ "configure",		ODBC_CONFIG_DSN },
	{ "configure_system",	ODBC_CONFIG_SYS_DSN },
	{ "remove",		ODBC_REMOVE_DSN },
	{ "remove_system", 	ODBC_REMOVE_SYS_DSN },
	{ NULL,			0 }
    };
    int flagIndex;		/* Index of the subcommand */
    WCHAR* driverName;		/* Name of the ODBC driver */
    WCHAR* attributes;		/* NULL-delimited attribute values */
    char errorMessage[SQL_MAX_MESSAGE_LENGTH+1];
				/* Error message from ODBC operations */







|







5211
5212
5213
5214
5215
5216
5217
5218
5219
5220
5221
5222
5223
5224
5225
	WORD value;
    } flags[] = {
	{ "add",		ODBC_ADD_DSN },
	{ "add_system",		ODBC_ADD_SYS_DSN },
	{ "configure",		ODBC_CONFIG_DSN },
	{ "configure_system",	ODBC_CONFIG_SYS_DSN },
	{ "remove",		ODBC_REMOVE_DSN },
	{ "remove_system",	ODBC_REMOVE_SYS_DSN },
	{ NULL,			0 }
    };
    int flagIndex;		/* Index of the subcommand */
    WCHAR* driverName;		/* Name of the ODBC driver */
    WCHAR* attributes;		/* NULL-delimited attribute values */
    char errorMessage[SQL_MAX_MESSAGE_LENGTH+1];
				/* Error message from ODBC operations */
5288
5289
5290
5291
5292
5293
5294
5295
5296
5297
5298
5299
5300
5301
5302
5303
	sep = "";
	Tcl_DStringInit(&retvalDS);
	errorCodeObj = Tcl_NewStringObj("TDBC ODBC", -1);
	Tcl_IncrRefCount(errorCodeObj);
	finished = 0;
	while (!finished) {
	    errorMessageLen = SQL_MAX_MESSAGE_LENGTH;
	    errorMessageStatus =
		SQLInstallerError(i, &errorCode, errorMessage,
				   SQL_MAX_MESSAGE_LENGTH-1, &errorMessageLen);
	    switch(errorMessageStatus) {
	    case SQL_SUCCESS:
		Tcl_DStringAppend(&retvalDS, sep, -1);
		Tcl_DStringInit(&errorMessageDS);
		(void)	Tcl_ExternalToUtfDString(NULL, errorMessage, errorMessageLen,
					 &errorMessageDS);







|
|







5289
5290
5291
5292
5293
5294
5295
5296
5297
5298
5299
5300
5301
5302
5303
5304
	sep = "";
	Tcl_DStringInit(&retvalDS);
	errorCodeObj = Tcl_NewStringObj("TDBC ODBC", -1);
	Tcl_IncrRefCount(errorCodeObj);
	finished = 0;
	while (!finished) {
	    errorMessageLen = SQL_MAX_MESSAGE_LENGTH;
	    errorMessageStatus = (RETCODE)
		SQLInstallerError((WORD)i, &errorCode, errorMessage,
				   SQL_MAX_MESSAGE_LENGTH-1, &errorMessageLen);
	    switch(errorMessageStatus) {
	    case SQL_SUCCESS:
		Tcl_DStringAppend(&retvalDS, sep, -1);
		Tcl_DStringInit(&errorMessageDS);
		(void)	Tcl_ExternalToUtfDString(NULL, errorMessage, errorMessageLen,
					 &errorMessageDS);
5388
5389
5390
5391
5392
5393
5394
5395
5396
5397
5398
5399
5400
5401
5402
	WORD value;
    } flags[] = {
	{ "add",		ODBC_ADD_DSN },
	{ "add_system",		ODBC_ADD_SYS_DSN },
	{ "configure",		ODBC_CONFIG_DSN },
	{ "configure_system",	ODBC_CONFIG_SYS_DSN },
	{ "remove",		ODBC_REMOVE_DSN },
	{ "remove_system", 	ODBC_REMOVE_SYS_DSN },
	{ NULL,			0 }
    };
    int flagIndex;		/* Index of the subcommand */
    Tcl_DString driverNameDS;
    Tcl_DString attributesDS;
    char* driverName;		/* Name of the ODBC driver in system
				 * encoding */







|







5389
5390
5391
5392
5393
5394
5395
5396
5397
5398
5399
5400
5401
5402
5403
	WORD value;
    } flags[] = {
	{ "add",		ODBC_ADD_DSN },
	{ "add_system",		ODBC_ADD_SYS_DSN },
	{ "configure",		ODBC_CONFIG_DSN },
	{ "configure_system",	ODBC_CONFIG_SYS_DSN },
	{ "remove",		ODBC_REMOVE_DSN },
	{ "remove_system",	ODBC_REMOVE_SYS_DSN },
	{ NULL,			0 }
    };
    int flagIndex;		/* Index of the subcommand */
    Tcl_DString driverNameDS;
    Tcl_DString attributesDS;
    char* driverName;		/* Name of the ODBC driver in system
				 * encoding */
5431
5432
5433
5434
5435
5436
5437
5438
5439
5440
5441
5442
5443
5444
5445
5446
5447
5448
5449
5450
5451
5452
5453
5454
5455
5456
5457
5458
5459
5460
5461
5462
5463
5464
5465
5466
5467
				  "operation", 0, &flagIndex) != TCL_OK) {
	return TCL_ERROR;
    }

    /* Convert driver name to the appropriate encoding */

    Tcl_DStringInit(&driverNameDS);
    p = Tcl_GetString(objv[2]);
    driverNameLen = objv[2]->length;
    (void)Tcl_UtfToExternalDString(NULL, p, driverNameLen, &driverNameDS);
    driverName = Tcl_DStringValue(&driverNameDS);
    driverNameLen = Tcl_DStringLength(&driverNameDS);

    /*
     * Convert driver attributes to the appropriate encoding, separated
     * by NUL bytes.
     */

    attrObj = Tcl_NewObj();
    Tcl_IncrRefCount(attrObj);
    sep = "";
    for (i = 3; i < objc; ++i) {
	Tcl_AppendToObj(attrObj, sep, -1);
	Tcl_AppendObjToObj(attrObj, objv[i]);
	sep = "\xc0\x80";
    }
    Tcl_AppendToObj(attrObj, "\xc0\x80", 2);
    Tcl_DStringInit(&attributesDS);
    p = Tcl_GetString(attrObj);
    attrLen = attrObj->length;
    (void)Tcl_UtfToExternalDString(NULL, p, attrLen, &attributesDS);
    attributes = Tcl_DStringValue(&attributesDS);
    attrLen = Tcl_DStringLength(&attributesDS);
    Tcl_DecrRefCount(attrObj);

    /*
     * Configure the data source







|
<



















|
<







5432
5433
5434
5435
5436
5437
5438
5439

5440
5441
5442
5443
5444
5445
5446
5447
5448
5449
5450
5451
5452
5453
5454
5455
5456
5457
5458
5459

5460
5461
5462
5463
5464
5465
5466
				  "operation", 0, &flagIndex) != TCL_OK) {
	return TCL_ERROR;
    }

    /* Convert driver name to the appropriate encoding */

    Tcl_DStringInit(&driverNameDS);
    p = Tcl_GetStringFromObj(objv[2], &driverNameLen);

    (void)Tcl_UtfToExternalDString(NULL, p, driverNameLen, &driverNameDS);
    driverName = Tcl_DStringValue(&driverNameDS);
    driverNameLen = Tcl_DStringLength(&driverNameDS);

    /*
     * Convert driver attributes to the appropriate encoding, separated
     * by NUL bytes.
     */

    attrObj = Tcl_NewObj();
    Tcl_IncrRefCount(attrObj);
    sep = "";
    for (i = 3; i < objc; ++i) {
	Tcl_AppendToObj(attrObj, sep, -1);
	Tcl_AppendObjToObj(attrObj, objv[i]);
	sep = "\xc0\x80";
    }
    Tcl_AppendToObj(attrObj, "\xc0\x80", 2);
    Tcl_DStringInit(&attributesDS);
    p = Tcl_GetStringFromObj(attrObj, &attrLen);

    (void)Tcl_UtfToExternalDString(NULL, p, attrLen, &attributesDS);
    attributes = Tcl_DStringValue(&attributesDS);
    attrLen = Tcl_DStringLength(&attributesDS);
    Tcl_DecrRefCount(attrObj);

    /*
     * Configure the data source
5480
5481
5482
5483
5484
5485
5486
5487
5488
5489
5490
5491
5492
5493
5494
5495
	sep = "";
	Tcl_DStringInit(&retvalDS);
	errorCodeObj = Tcl_NewStringObj("TDBC ODBC", -1);
	Tcl_IncrRefCount(errorCodeObj);
	finished = 0;
	while (!finished) {
	    errorMessageLen = SQL_MAX_MESSAGE_LENGTH;
	    errorMessageStatus =
		SQLInstallerError(i, &errorCode, errorMessage,
				  SQL_MAX_MESSAGE_LENGTH-1, &errorMessageLen);
	    switch(errorMessageStatus) {
	    case SQL_SUCCESS:
		Tcl_DStringAppend(&retvalDS, sep, -1);
		Tcl_DStringInit(&errorMessageDS);
		(void)Tcl_ExternalToUtfDString(NULL, errorMessage, errorMessageLen,
					 &errorMessageDS);







|
|







5479
5480
5481
5482
5483
5484
5485
5486
5487
5488
5489
5490
5491
5492
5493
5494
	sep = "";
	Tcl_DStringInit(&retvalDS);
	errorCodeObj = Tcl_NewStringObj("TDBC ODBC", -1);
	Tcl_IncrRefCount(errorCodeObj);
	finished = 0;
	while (!finished) {
	    errorMessageLen = SQL_MAX_MESSAGE_LENGTH;
	    errorMessageStatus = (RETCODE)
		SQLInstallerError((WORD)i, &errorCode, errorMessage,
				  SQL_MAX_MESSAGE_LENGTH-1, &errorMessageLen);
	    switch(errorMessageStatus) {
	    case SQL_SUCCESS:
		Tcl_DStringAppend(&retvalDS, sep, -1);
		Tcl_DStringInit(&errorMessageDS);
		(void)Tcl_ExternalToUtfDString(NULL, errorMessage, errorMessageLen,
					 &errorMessageDS);
Changes to library/tdbcodbc.tcl.
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89

    # The 'tables' method returns a dictionary describing the tables
    # in the database

    method tables {{pattern %}} {
	set stmt [::tdbc::odbc::tablesStatement create \
		      Stmt::[incr statementSeq] [self] $pattern]
       	set status [catch {
	    set retval {}
	    $stmt foreach -as dicts row {
		if {[dict exists $row TABLE_NAME]} {
		    dict set retval [dict get $row TABLE_NAME] $row
		}
	    }
	    set retval







|







75
76
77
78
79
80
81
82
83
84
85
86
87
88
89

    # The 'tables' method returns a dictionary describing the tables
    # in the database

    method tables {{pattern %}} {
	set stmt [::tdbc::odbc::tablesStatement create \
		      Stmt::[incr statementSeq] [self] $pattern]
	set status [catch {
	    set retval {}
	    $stmt foreach -as dicts row {
		if {[dict exists $row TABLE_NAME]} {
		    dict set retval [dict get $row TABLE_NAME] $row
		}
	    }
	    set retval
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160

    # The 'primarykeys' method returns a dictionary describing the primary
    # keys of a table

    method primarykeys {tableName} {
	set stmt [::tdbc::odbc::primarykeysStatement create \
		      Stmt::[incr statementSeq] [self] $tableName]
       	set status [catch {
	    set retval {}
	    $stmt foreach -as dicts row {
		foreach {odbcKey tdbcKey} {
		    TABLE_CAT		tableCatalog
		    TABLE_SCHEM		tableSchema
		    TABLE_NAME		tableName
		    COLUMN_NAME		columnName







|







146
147
148
149
150
151
152
153
154
155
156
157
158
159
160

    # The 'primarykeys' method returns a dictionary describing the primary
    # keys of a table

    method primarykeys {tableName} {
	set stmt [::tdbc::odbc::primarykeysStatement create \
		      Stmt::[incr statementSeq] [self] $tableName]
	set status [catch {
	    set retval {}
	    $stmt foreach -as dicts row {
		foreach {odbcKey tdbcKey} {
		    TABLE_CAT		tableCatalog
		    TABLE_SCHEM		tableSchema
		    TABLE_NAME		tableName
		    COLUMN_NAME		columnName
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190

    # The 'foreignkeys' method returns a dictionary describing the foreign
    # keys of a table

    method foreignkeys {args} {
	set stmt [::tdbc::odbc::foreignkeysStatement create \
		      Stmt::[incr statementSeq] [self] {*}$args]
       	set status [catch {
	    set fkseq 0
	    set retval {}
	    $stmt foreach -as dicts row {
		foreach {odbcKey tdbcKey} {
		    PKTABLE_CAT		primaryCatalog
		    PKTABLE_SCHEM	primarySchema
		    PKTABLE_NAME	primaryTable







|







176
177
178
179
180
181
182
183
184
185
186
187
188
189
190

    # The 'foreignkeys' method returns a dictionary describing the foreign
    # keys of a table

    method foreignkeys {args} {
	set stmt [::tdbc::odbc::foreignkeysStatement create \
		      Stmt::[incr statementSeq] [self] {*}$args]
	set status [catch {
	    set fkseq 0
	    set retval {}
	    $stmt foreach -as dicts row {
		foreach {odbcKey tdbcKey} {
		    PKTABLE_CAT		primaryCatalog
		    PKTABLE_SCHEM	primarySchema
		    PKTABLE_NAME	primaryTable
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237

    # The 'evaldirect' evaluates driver-native SQL code without preparing it,
    # and returns a list of dicts (similar to '$connection allrows -as dicts').

    method evaldirect {sqlStatement} {
	set stmt [::tdbc::odbc::evaldirectStatement create \
		      Stmt::[incr statementSeq] [self] $sqlStatement]
       	set status [catch {
	    $stmt allrows -as dicts
	} result options]
	catch {rename $stmt {}}
	return -level 0 -options $options $result
    }

    # The 'prepareCall' method gives a portable interface to prepare







|







223
224
225
226
227
228
229
230
231
232
233
234
235
236
237

    # The 'evaldirect' evaluates driver-native SQL code without preparing it,
    # and returns a list of dicts (similar to '$connection allrows -as dicts').

    method evaldirect {sqlStatement} {
	set stmt [::tdbc::odbc::evaldirectStatement create \
		      Stmt::[incr statementSeq] [self] $sqlStatement]
	set status [catch {
	    $stmt allrows -as dicts
	} result options]
	catch {rename $stmt {}}
	return -level 0 -options $options $result
    }

    # The 'prepareCall' method gives a portable interface to prepare
Changes to tests/tdbcodbc.test.
3806
3807
3808
3809
3810
3811
3812
3813
3814
3815
3816
3817
3818
3819
3820
3821
3822
3823
3824
		@idnum INTEGER OUTPUT
	    AS
	    SELECT @idnum = idnum FROM people WHERE name = @name
	}
	catch {unset stmt}
    }
    -body {
 	set stmt [::db prepare {
 	    DECLARE @x AS INTEGER;
 	    EXECUTE find_person :name, @x OUTPUT;
	    SELECT @x AS result
 	}]
	$stmt allrows {name barney}
    }
    -cleanup {
	if {[info exists stmt]} {
	    rename $stmt {}
	}
	db allrows {







|
|
|

|







3806
3807
3808
3809
3810
3811
3812
3813
3814
3815
3816
3817
3818
3819
3820
3821
3822
3823
3824
		@idnum INTEGER OUTPUT
	    AS
	    SELECT @idnum = idnum FROM people WHERE name = @name
	}
	catch {unset stmt}
    }
    -body {
	set stmt [::db prepare {
	    DECLARE @x AS INTEGER;
	    EXECUTE find_person :name, @x OUTPUT;
	    SELECT @x AS result
	}]
	$stmt allrows {name barney}
    }
    -cleanup {
	if {[info exists stmt]} {
	    rename $stmt {}
	}
	db allrows {
3855
3856
3857
3858
3859
3860
3861
3862
3863
3864
3865
3866
3867
3868
3869
		@idnum INTEGER OUTPUT
	    AS
	    SELECT @idnum = idnum FROM people WHERE name = @name
	}
	catch {unset stmt}
    }
    -body {
 	set stmt [::db prepare {{CALL find_person(:name, :x)}}]
	$stmt paramtype x out integer 10
	puts [$stmt params]
	$stmt allrows {name barney}
    }
    -cleanup {
	if {[info exists stmt]} {
	    rename $stmt {}







|







3855
3856
3857
3858
3859
3860
3861
3862
3863
3864
3865
3866
3867
3868
3869
		@idnum INTEGER OUTPUT
	    AS
	    SELECT @idnum = idnum FROM people WHERE name = @name
	}
	catch {unset stmt}
    }
    -body {
	set stmt [::db prepare {{CALL find_person(:name, :x)}}]
	$stmt paramtype x out integer 10
	puts [$stmt params]
	$stmt allrows {name barney}
    }
    -cleanup {
	if {[info exists stmt]} {
	    rename $stmt {}
Changes to win/makefile.vc.
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
!if $(TCL_MAJOR_VERSION) == 8 || "$(TCL_BUILD_FOR)" == "8"
TDBCSTUBLIBNAME	 = tdbcstub$(TDBC_VERSION).lib
TDBC_LIB_FILE	 = tdbc$(TDBC_VERSION)$(SUFX).dll
!else
TDBCSTUBLIBNAME	 = tdbcstub.lib
TDBC_LIB_FILE	 = tcl9tdbc$(TDBC_VERSION).dll
!endif
TDBCSTUBLIB 	 = $(TDBC_DIR)\win\$(BUILDDIRTOP)\$(TDBCSTUBLIBNAME)
TDBC_BIN_DIR     = $(TDBC_DIR)/win/$(BUILDDIRTOP)

PRJ_INCLUDES	= -I"$(TDBC_GENERIC_DIR)"

!if !$(STATIC_BUILD)
PRJ_LIBS  = $(TDBCSTUBLIB)
!endif







|







71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
!if $(TCL_MAJOR_VERSION) == 8 || "$(TCL_BUILD_FOR)" == "8"
TDBCSTUBLIBNAME	 = tdbcstub$(TDBC_VERSION).lib
TDBC_LIB_FILE	 = tdbc$(TDBC_VERSION)$(SUFX).dll
!else
TDBCSTUBLIBNAME	 = tdbcstub.lib
TDBC_LIB_FILE	 = tcl9tdbc$(TDBC_VERSION).dll
!endif
TDBCSTUBLIB	 = $(TDBC_DIR)\win\$(BUILDDIRTOP)\$(TDBCSTUBLIBNAME)
TDBC_BIN_DIR     = $(TDBC_DIR)/win/$(BUILDDIRTOP)

PRJ_INCLUDES	= -I"$(TDBC_GENERIC_DIR)"

!if !$(STATIC_BUILD)
PRJ_LIBS  = $(TDBCSTUBLIB)
!endif
115
116
117
118
119
120
121
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

test: setup $(PROJECT)

test-jet: setup $(PROJECT)
	@echo testing tdbcodbc against Jet
	@set TDBCODBC_TYPE=jet
# the following is identical for all 3 tests
        @set TCL_LIBRARY=$(TCL_LIBRARY:\=/)
        @set TCLLIBPATH=$(OUT_DIR_PATH:\=/)
	@set TDBC_LIBRARY=$(LIBDIR:\=/)
	@$(CPY) $(LIBDIR)\*.tcl $(OUT_DIR)
!if $(TCLINSTALL)
        @set PATH=$(_TCLDIR)\bin;$(PATH)
	$(DEBUGGER) $(TCLSH) "$(ROOT:\=/)/tests/all.tcl" $(TESTFLAGS)
!else
        @set PATH=$(_TCLDIR)\win\$(BUILDDIRTOP);$(PATH)
	$(DEBUGGER) $(TCLSH) "$(ROOT:\=/)/tests/all.tcl" $(TESTFLAGS) \
		-load "package ifneeded tdbc::odbc $(DOTVERSION) \
			{source {$(LIBDIR:\=/)/tdbcodbc.tcl};load {$(PRJLIB:\=/)} [string totitle $(PROJECT)]};\
		package ifneeded tdbc $(TDBC_DOTVERSION) \
			{source {$(TDBC_BIN_DIR:\=/)/tdbc.tcl};load {$(TDBC_BIN_DIR:\=/)/$(TDBC_LIB_FILE)} Tdbc}"
!endif

test-sqlserver: setup $(PROJECT)
	@echo testing tdbcodbc against SQL Server
	@set TDBCODBC_TYPE=sqlserver
# the following is identical for all 3 tests
        @set TCL_LIBRARY=$(TCL_LIBRARY:\=/)
        @set TCLLIBPATH=$(OUT_DIR_PATH:\=/)
	@set TDBC_LIBRARY=$(LIBDIR:\=/)
	@$(CPY) $(LIBDIR)\*.tcl $(OUT_DIR)
!if $(TCLINSTALL)
        @set PATH=$(_TCLDIR)\bin;$(PATH)
	$(DEBUGGER) $(TCLSH) "$(ROOT:\=/)/tests/all.tcl" $(TESTFLAGS)
!else
        @set PATH=$(_TCLDIR)\win\$(BUILDDIRTOP);$(PATH)
	$(DEBUGGER) $(TCLSH) "$(ROOT:\=/)/tests/all.tcl" $(TESTFLAGS) \
		-load "package ifneeded tdbc::odbc $(DOTVERSION) \
			{source {$(LIBDIR:\=/)/tdbcodbc.tcl};load {$(PRJLIB:\=/)} [string totitle $(PROJECT)]};\
		package ifneeded tdbc $(TDBC_DOTVERSION) \
			{source {$(TDBC_BIN_DIR:\=/)/tdbc.tcl};load {$(TDBC_BIN_DIR:\=/)/$(TDBC_LIB_FILE)} Tdbc}"
!endif

test-sqlite: setup $(PROJECT)
	@echo testing tdbcodbc against SQLite
	@set TDBCODBC_TYPE=sqlite
# the following is identical for all 3 tests
        @set TCL_LIBRARY=$(TCL_LIBRARY:\=/)
        @set TCLLIBPATH=$(OUT_DIR_PATH:\=/)
	@set TDBC_LIBRARY=$(LIBDIR:\=/)
	@$(CPY) $(LIBDIR)\*.tcl $(OUT_DIR)
!if $(TCLINSTALL)
        @set PATH=$(_TCLDIR)\bin;$(PATH)
	$(DEBUGGER) $(TCLSH) "$(ROOT:\=/)/tests/all.tcl" $(TESTFLAGS)
!else
        @set PATH=$(_TCLDIR)\win\$(BUILDDIRTOP);$(PATH)
	$(DEBUGGER) $(TCLSH) "$(ROOT:\=/)/tests/all.tcl" $(TESTFLAGS) \
		-load "package ifneeded tdbc::odbc $(DOTVERSION) \
			{source {$(LIBDIR:\=/)/tdbcodbc.tcl};load {$(PRJLIB:\=/)} [string totitle $(PROJECT)]};\
		package ifneeded tdbc $(TDBC_DOTVERSION) \
			{source {$(TDBC_BIN_DIR:\=/)/tdbc.tcl};load {$(TDBC_BIN_DIR:\=/)/$(TDBC_LIB_FILE)} Tdbc}"
!endif


# Explicit dependency rules
$(GENERICDIR)\tdbcodbc.c : $(TMP_DIR)\tdbcOdbcUuid.h







|
|



|


|











|
|



|


|











|
|



|


|










115
116
117
118
119
120
121
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

test: setup $(PROJECT)

test-jet: setup $(PROJECT)
	@echo testing tdbcodbc against Jet
	@set TDBCODBC_TYPE=jet
# the following is identical for all 3 tests
	@set TCL_LIBRARY=$(TCL_LIBRARY:\=/)
	@set TCLLIBPATH=$(OUT_DIR_PATH:\=/)
	@set TDBC_LIBRARY=$(LIBDIR:\=/)
	@$(CPY) $(LIBDIR)\*.tcl $(OUT_DIR)
!if $(TCLINSTALL)
	@set PATH=$(_TCLDIR)\bin;$(PATH)
	$(DEBUGGER) $(TCLSH) "$(ROOT:\=/)/tests/all.tcl" $(TESTFLAGS)
!else
	@set PATH=$(_TCLDIR)\win\$(BUILDDIRTOP);$(PATH)
	$(DEBUGGER) $(TCLSH) "$(ROOT:\=/)/tests/all.tcl" $(TESTFLAGS) \
		-load "package ifneeded tdbc::odbc $(DOTVERSION) \
			{source {$(LIBDIR:\=/)/tdbcodbc.tcl};load {$(PRJLIB:\=/)} [string totitle $(PROJECT)]};\
		package ifneeded tdbc $(TDBC_DOTVERSION) \
			{source {$(TDBC_BIN_DIR:\=/)/tdbc.tcl};load {$(TDBC_BIN_DIR:\=/)/$(TDBC_LIB_FILE)} Tdbc}"
!endif

test-sqlserver: setup $(PROJECT)
	@echo testing tdbcodbc against SQL Server
	@set TDBCODBC_TYPE=sqlserver
# the following is identical for all 3 tests
	@set TCL_LIBRARY=$(TCL_LIBRARY:\=/)
	@set TCLLIBPATH=$(OUT_DIR_PATH:\=/)
	@set TDBC_LIBRARY=$(LIBDIR:\=/)
	@$(CPY) $(LIBDIR)\*.tcl $(OUT_DIR)
!if $(TCLINSTALL)
	@set PATH=$(_TCLDIR)\bin;$(PATH)
	$(DEBUGGER) $(TCLSH) "$(ROOT:\=/)/tests/all.tcl" $(TESTFLAGS)
!else
	@set PATH=$(_TCLDIR)\win\$(BUILDDIRTOP);$(PATH)
	$(DEBUGGER) $(TCLSH) "$(ROOT:\=/)/tests/all.tcl" $(TESTFLAGS) \
		-load "package ifneeded tdbc::odbc $(DOTVERSION) \
			{source {$(LIBDIR:\=/)/tdbcodbc.tcl};load {$(PRJLIB:\=/)} [string totitle $(PROJECT)]};\
		package ifneeded tdbc $(TDBC_DOTVERSION) \
			{source {$(TDBC_BIN_DIR:\=/)/tdbc.tcl};load {$(TDBC_BIN_DIR:\=/)/$(TDBC_LIB_FILE)} Tdbc}"
!endif

test-sqlite: setup $(PROJECT)
	@echo testing tdbcodbc against SQLite
	@set TDBCODBC_TYPE=sqlite
# the following is identical for all 3 tests
	@set TCL_LIBRARY=$(TCL_LIBRARY:\=/)
	@set TCLLIBPATH=$(OUT_DIR_PATH:\=/)
	@set TDBC_LIBRARY=$(LIBDIR:\=/)
	@$(CPY) $(LIBDIR)\*.tcl $(OUT_DIR)
!if $(TCLINSTALL)
	@set PATH=$(_TCLDIR)\bin;$(PATH)
	$(DEBUGGER) $(TCLSH) "$(ROOT:\=/)/tests/all.tcl" $(TESTFLAGS)
!else
	@set PATH=$(_TCLDIR)\win\$(BUILDDIRTOP);$(PATH)
	$(DEBUGGER) $(TCLSH) "$(ROOT:\=/)/tests/all.tcl" $(TESTFLAGS) \
		-load "package ifneeded tdbc::odbc $(DOTVERSION) \
			{source {$(LIBDIR:\=/)/tdbcodbc.tcl};load {$(PRJLIB:\=/)} [string totitle $(PROJECT)]};\
		package ifneeded tdbc $(TDBC_DOTVERSION) \
			{source {$(TDBC_BIN_DIR:\=/)/tdbc.tcl};load {$(TDBC_BIN_DIR:\=/)/$(TDBC_LIB_FILE)} Tdbc}"
!endif


# Explicit dependency rules
$(GENERICDIR)\tdbcodbc.c : $(TMP_DIR)\tdbcOdbcUuid.h
Changes to win/nmakehlp.c.
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#define _CRT_SECURE_NO_DEPRECATE
#include <windows.h>
#ifdef _MSC_VER
#pragma comment (lib, "user32.lib")
#pragma comment (lib, "kernel32.lib")
#endif
#include <stdio.h>
#include <math.h>

/*
 * This library is required for x64 builds with _some_ versions of MSVC
 */
#if defined(_M_IA64) || defined(_M_AMD64)
#if _MSC_VER >= 1400 && _MSC_VER < 1500
#pragma comment(lib, "bufferoverflowU")







<







15
16
17
18
19
20
21

22
23
24
25
26
27
28
#define _CRT_SECURE_NO_DEPRECATE
#include <windows.h>
#ifdef _MSC_VER
#pragma comment (lib, "user32.lib")
#pragma comment (lib, "kernel32.lib")
#endif
#include <stdio.h>


/*
 * This library is required for x64 builds with _some_ versions of MSVC
 */
#if defined(_M_IA64) || defined(_M_AMD64)
#if _MSC_VER >= 1400 && _MSC_VER < 1500
#pragma comment(lib, "bufferoverflowU")
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
    SetEnvironmentVariable("LINK", "");

    if (argc > 1 && *argv[1] == '-') {
	switch (*(argv[1]+1)) {
	case 'c':
	    if (argc != 3) {
		chars = snprintf(msg, sizeof(msg) - 1,
		        "usage: %s -c <compiler option>\n"
			"Tests for whether cl.exe supports an option\n"
			"exitcodes: 0 == no, 1 == yes, 2 == error\n", argv[0]);
		WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars,
			&dwWritten, NULL);
		return 2;
	    }
	    return CheckForCompilerFeature(argv[2]);
	case 'l':
	    if (argc < 3) {
		chars = snprintf(msg, sizeof(msg) - 1,
	       		"usage: %s -l <linker option> ?<mandatory option> ...?\n"
			"Tests for whether link.exe supports an option\n"
			"exitcodes: 0 == no, 1 == yes, 2 == error\n", argv[0]);
		WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars,
			&dwWritten, NULL);
		return 2;
	    }
	    return CheckForLinkerFeature(&argv[2], argc-2);







|










|







86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
    SetEnvironmentVariable("LINK", "");

    if (argc > 1 && *argv[1] == '-') {
	switch (*(argv[1]+1)) {
	case 'c':
	    if (argc != 3) {
		chars = snprintf(msg, sizeof(msg) - 1,
			"usage: %s -c <compiler option>\n"
			"Tests for whether cl.exe supports an option\n"
			"exitcodes: 0 == no, 1 == yes, 2 == error\n", argv[0]);
		WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars,
			&dwWritten, NULL);
		return 2;
	    }
	    return CheckForCompilerFeature(argv[2]);
	case 'l':
	    if (argc < 3) {
		chars = snprintf(msg, sizeof(msg) - 1,
			"usage: %s -l <linker option> ?<mandatory option> ...?\n"
			"Tests for whether link.exe supports an option\n"
			"exitcodes: 0 == no, 1 == yes, 2 == error\n", argv[0]);
		WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars,
			&dwWritten, NULL);
		return 2;
	    }
	    return CheckForLinkerFeature(&argv[2], argc-2);
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333

    /*
     * Look for the commandline warning code in both streams.
     *  - in MSVC 6 & 7 we get D4002, in MSVC 8 we get D9002.
     */

    return !(strstr(Out.buffer, "D4002") != NULL
             || strstr(Err.buffer, "D4002") != NULL
             || strstr(Out.buffer, "D9002") != NULL
             || strstr(Err.buffer, "D9002") != NULL
             || strstr(Out.buffer, "D2021") != NULL
             || strstr(Err.buffer, "D2021") != NULL);
}

static int
CheckForLinkerFeature(
    char **options,
    int count)
{







|
|
|
|
|







314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332

    /*
     * Look for the commandline warning code in both streams.
     *  - in MSVC 6 & 7 we get D4002, in MSVC 8 we get D9002.
     */

    return !(strstr(Out.buffer, "D4002") != NULL
	    || strstr(Err.buffer, "D4002") != NULL
	    || strstr(Out.buffer, "D9002") != NULL
	    || strstr(Err.buffer, "D9002") != NULL
	    || strstr(Out.buffer, "D2021") != NULL
	    || strstr(Err.buffer, "D2021") != NULL);
}

static int
CheckForLinkerFeature(
    char **options,
    int count)
{
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
    const char *substring)
{
    return (strstr(string, substring) != NULL);
}

/*
 * GetVersionFromFile --
 * 	Looks for a match string in a file and then returns the version
 * 	following the match where a version is anything acceptable to
 * 	package provide or package ifneeded.
 */

static const char *
GetVersionFromFile(
    const char *filename,
    const char *match,
    int numdots)







|
|
|







489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
    const char *substring)
{
    return (strstr(string, substring) != NULL);
}

/*
 * GetVersionFromFile --
 *	Looks for a match string in a file and then returns the version
 *	following the match where a version is anything acceptable to
 *	package provide or package ifneeded.
 */

static const char *
GetVersionFromFile(
    const char *filename,
    const char *match,
    int numdots)
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
 *	option here to handle autoconf style substitutions.
 *	The substitution file is whitespace and line delimited. The file should
 *	consist of lines matching the regular expression:
 *	  \s*\S+\s+\S*$
 *
 *	Usage is something like:
 *	  nmakehlp -S << $** > $@
 *        @PACKAGE_NAME@ $(PACKAGE_NAME)
 *        @PACKAGE_VERSION@ $(PACKAGE_VERSION)
 *        <<
 */

static int
SubstituteFile(
    const char *substitutions,
    const char *filename)
{







|
|
|







596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
 *	option here to handle autoconf style substitutions.
 *	The substitution file is whitespace and line delimited. The file should
 *	consist of lines matching the regular expression:
 *	  \s*\S+\s+\S*$
 *
 *	Usage is something like:
 *	  nmakehlp -S << $** > $@
 *	    @PACKAGE_NAME@ $(PACKAGE_NAME)
 *	    @PACKAGE_VERSION@ $(PACKAGE_VERSION)
 *	    <<
 */

static int
SubstituteFile(
    const char *substitutions,
    const char *filename)
{
744
745
746
747
748
749
750
751
752

753
754
755
756
757
758
759
760
761
762
763

764
765
766

767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
     * 1 -> FindExSearchLimitToDirectories,
     * as these are not defined in Visual C++ 6
     */
    hSearch = FindFirstFileEx(path, 0, &finfo, 1, NULL, 0);
#else
    hSearch = FindFirstFile(path, &finfo);
#endif
    if (hSearch == INVALID_HANDLE_VALUE)
	return 1; /* Not found */


    /* Loop through all subdirs checking if the keypath is under there */
    ret = 1; /* Assume not found */
    do {
	int sublen;
	/*
	 * We need to check it is a directory despite the
	 * FindExSearchLimitToDirectories in the above call. See SDK docs
	 */
	if ((finfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
	    continue;

	sublen = strlen(finfo.cFileName);
	if ((dirlen+1+sublen+1+keylen+1) > sizeof(path))
	    continue;		/* Path does not fit, assume not matched */

	strncpy(path+dirlen+1, finfo.cFileName, sublen);
	path[dirlen+1+sublen] = '\\';
	strncpy(path+dirlen+1+sublen+1, keypath, keylen+1);
	if (FileExists(path)) {
	    /* Found a match, print to stdout */
	    path[dirlen+1+sublen] = '\0';
	    QualifyPath(path);
	    ret = 0;
	    break;
	}
    } while (FindNextFile(hSearch, &finfo));
    FindClose(hSearch);
    return ret;
}

/*
 * LocateDependency --
 *
 *	Locates a dependency for a package.
 *        keypath - a relative path within the package directory
 *          that is used to confirm it is the correct directory.
 *	The search path for the package directory is currently only
 *      the parent and grandparent of the current working directory.
 *      If found, the command prints
 *         name_DIRPATH=<full path of located directory>
 *      and returns 0. If not found, does not print anything and returns 1.
 */
static int LocateDependency(const char *keypath)
{
    size_t i;
    int ret;
    static const char *paths[] = {"..", "..\\..", "..\\..\\.."};








|

>









|

>

|

>



















|
|

|
|
|
|







743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
     * 1 -> FindExSearchLimitToDirectories,
     * as these are not defined in Visual C++ 6
     */
    hSearch = FindFirstFileEx(path, 0, &finfo, 1, NULL, 0);
#else
    hSearch = FindFirstFile(path, &finfo);
#endif
    if (hSearch == INVALID_HANDLE_VALUE) {
	return 1; /* Not found */
    }

    /* Loop through all subdirs checking if the keypath is under there */
    ret = 1; /* Assume not found */
    do {
	int sublen;
	/*
	 * We need to check it is a directory despite the
	 * FindExSearchLimitToDirectories in the above call. See SDK docs
	 */
	if ((finfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) {
	    continue;
	}
	sublen = strlen(finfo.cFileName);
	if ((dirlen+1+sublen+1+keylen+1) > sizeof(path)) {
	    continue;		/* Path does not fit, assume not matched */
	}
	strncpy(path+dirlen+1, finfo.cFileName, sublen);
	path[dirlen+1+sublen] = '\\';
	strncpy(path+dirlen+1+sublen+1, keypath, keylen+1);
	if (FileExists(path)) {
	    /* Found a match, print to stdout */
	    path[dirlen+1+sublen] = '\0';
	    QualifyPath(path);
	    ret = 0;
	    break;
	}
    } while (FindNextFile(hSearch, &finfo));
    FindClose(hSearch);
    return ret;
}

/*
 * LocateDependency --
 *
 *	Locates a dependency for a package.
 *	    keypath - a relative path within the package directory
 *	      that is used to confirm it is the correct directory.
 *	The search path for the package directory is currently only
 *	    the parent and grandparent of the current working directory.
 *	    If found, the command prints
 *	      name_DIRPATH=<full path of located directory>
 *	    and returns 0. If not found, does not print anything and returns 1.
 */
static int LocateDependency(const char *keypath)
{
    size_t i;
    int ret;
    static const char *paths[] = {"..", "..\\..", "..\\..\\.."};