// will overwrite the errors of the previously destroyed wxDb object in
// this variable. NOTE: This occurs during a CLOSE, not a FREEing of the
// connection
-wxChar DBerrorList[DB_MAX_ERROR_HISTORY][DB_MAX_ERROR_MSG_LEN];
+wxChar DBerrorList[DB_MAX_ERROR_HISTORY][DB_MAX_ERROR_MSG_LEN+1];
// This type defines the return row-struct form
{
wxASSERT(dsn.Length() < sizeof(Dsn));
- wxStrcpy(Dsn,dsn);
+ wxStrncpy(Dsn, dsn, sizeof(Dsn)-1);
+ Dsn[sizeof(Dsn)-1] = 0; // Prevent buffer overrun
} // wxDbConnectInf::SetDsn()
void wxDbConnectInf::SetUserID(const wxString &uid)
{
wxASSERT(uid.Length() < sizeof(Uid));
- wxStrcpy(Uid, uid);
+ wxStrncpy(Uid, uid, sizeof(Uid)-1);
+ Uid[sizeof(Uid)-1] = 0; // Prevent buffer overrun
} // wxDbConnectInf::SetUserID()
{
wxASSERT(password.Length() < sizeof(AuthStr));
- wxStrcpy(AuthStr, password);
+ wxStrncpy(AuthStr, password, sizeof(AuthStr)-1);
+ AuthStr[sizeof(AuthStr)-1] = 0; // Prevent buffer overrun
} // wxDbConnectInf::SetPassword()
void wxDbConnectInf::SetConnectionStr(const wxString &connectStr)
useConnectionStr = wxStrlen(connectStr) > 0;
- wxStrcpy(ConnectionStr, connectStr);
+ wxStrncpy(ConnectionStr, connectStr, sizeof(ConnectionStr)-1);
+ ConnectionStr[sizeof(ConnectionStr)-1] = 0; // Prevent buffer overrun
} // wxDbConnectInf::SetConnectionStr()
if (i_dbDataType == 0) // Filter unsupported dbDataTypes
{
- if ((i_sqlDataType == SQL_VARCHAR) || (i_sqlDataType == SQL_LONGVARCHAR))
+ if ((i_sqlDataType == SQL_VARCHAR)
+#if wxUSE_UNICODE
+ #if defined(SQL_WCHAR)
+ || (i_sqlDataType == SQL_WCHAR)
+ #endif
+ #if defined(SQL_WVARCHAR)
+ || (i_sqlDataType == SQL_WVARCHAR)
+ #endif
+#endif
+ || (i_sqlDataType == SQL_LONGVARCHAR))
i_dbDataType = DB_DATA_TYPE_VARCHAR;
if ((i_sqlDataType == SQL_C_DATE) || (i_sqlDataType == SQL_C_TIMESTAMP))
i_dbDataType = DB_DATA_TYPE_DATE;
if (i_sqlDataType == SQL_C_BIT)
i_dbDataType = DB_DATA_TYPE_INTEGER;
if (i_sqlDataType == SQL_NUMERIC)
- i_dbDataType = DB_DATA_TYPE_VARCHAR;
+ i_dbDataType = DB_DATA_TYPE_VARCHAR; // glt - ??? is this right?
if (i_sqlDataType == SQL_REAL)
i_dbDataType = DB_DATA_TYPE_FLOAT;
if (i_sqlDataType == SQL_C_BINARY)
|| Dbms() == dbmsXBASE_SEQUITER )
UserID.Empty();
- // Oracle user names may only be in uppercase, so force
- // the name to uppercase
- if (Dbms() == dbmsORACLE)
+ // Some databases require user names to be specified in uppercase,
+ // so force the name to uppercase
+ if ((Dbms() == dbmsORACLE) ||
+ (Dbms() == dbmsMAXDB))
UserID = UserID.Upper();
return UserID.c_str();
} // wxDb::convertUserID()
-bool wxDb::open(bool failOnDataTypeUnsupported)
+bool wxDb::determineDataTypes(bool failOnDataTypeUnsupported)
{
-/*
- If using Intersolv branded ODBC drivers, this is the place where you would substitute
- your branded driver license information
+ size_t iIndex;
- SQLSetConnectOption(hdbc, 1041, (UDWORD) wxEmptyString);
- SQLSetConnectOption(hdbc, 1042, (UDWORD) wxEmptyString);
-*/
+ // These are the possible SQL types we check for use against the datasource we are connected
+ // to for the purpose of determining which data type to use for the basic character strings
+ // column types
+ //
+ // NOTE: The first type in this enumeration that is determined to be supported by the
+ // datasource/driver is the one that will be used.
+ SWORD PossibleSqlCharTypes[] = {
+#if wxUSE_UNICODE && defined(SQL_WVARCHAR)
+ SQL_WVARCHAR,
+#endif
+ SQL_VARCHAR,
+#if wxUSE_UNICODE && defined(SQL_WVARCHAR)
+ SQL_WCHAR,
+#endif
+ SQL_CHAR
+ };
- // Mark database as open
- dbIsOpen = true;
+ // These are the possible SQL types we check for use against the datasource we are connected
+ // to for the purpose of determining which data type to use for the basic non-floating point
+ // column types
+ //
+ // NOTE: The first type in this enumeration that is determined to be supported by the
+ // datasource/driver is the one that will be used.
+ SWORD PossibleSqlIntegerTypes[] = {
+ SQL_INTEGER
+ };
- // Allocate a statement handle for the database connection
- if (SQLAllocStmt(hdbc, &hstmt) != SQL_SUCCESS)
- return(DispAllErrors(henv, hdbc));
+ // These are the possible SQL types we check for use against the datasource we are connected
+ // to for the purpose of determining which data type to use for the basic floating point number
+ // column types
+ //
+ // NOTE: The first type in this enumeration that is determined to be supported by the
+ // datasource/driver is the one that will be used.
+ SWORD PossibleSqlFloatTypes[] = {
+ SQL_DOUBLE,
+ SQL_REAL,
+ SQL_FLOAT,
+ SQL_DECIMAL,
+ SQL_NUMERIC
+ };
- // Set Connection Options
- if (!setConnectionOptions())
- return false;
+ // These are the possible SQL types we check for use agains the datasource we are connected
+ // to for the purpose of determining which data type to use for the date/time column types
+ //
+ // NOTE: The first type in this enumeration that is determined to be supported by the
+ // datasource/driver is the one that will be used.
+ SWORD PossibleSqlDateTypes[] = {
+ SQL_TIMESTAMP,
+ SQL_DATE,
+#ifdef SQL_DATETIME
+ SQL_DATETIME
+#endif
+ };
+
+ // These are the possible SQL types we check for use agains the datasource we are connected
+ // to for the purpose of determining which data type to use for the BLOB column types.
+ //
+ // NOTE: The first type in this enumeration that is determined to be supported by the
+ // datasource/driver is the one that will be used.
+ SWORD PossibleSqlBlobTypes[] = {
+ SQL_LONGVARBINARY,
+ SQL_VARBINARY
+ };
- // Query the data source for inf. about itself
- if (!getDbInfo(failOnDataTypeUnsupported))
- return false;
// Query the data source regarding data type information
// for all of the possible SQL data types to see which ones were supported. If
// a type is not supported, the SQLFetch() that's called from getDataTypeInfo()
// fails with SQL_NO_DATA_FOUND. This is ugly because I'm sure the three SQL data
- // types I've selected below will not alway's be what we want. These are just
+ // types I've selected below will not always be what we want. These are just
// what happened to work against an Oracle 7/Intersolv combination. The following is
// a complete list of the results I got back against the Oracle 7 database:
//
// SQL_DOUBLE type name = 'DOUBLE', Precision = 15
// SQL_INTEGER type name = 'LONG', Precision = 10
- // VARCHAR = Variable length character string
- if (!getDataTypeInfo(SQL_VARCHAR, typeInfVarchar))
- if (!getDataTypeInfo(SQL_CHAR, typeInfVarchar))
- return false;
- else
- typeInfVarchar.FsqlType = SQL_CHAR;
- else
- typeInfVarchar.FsqlType = SQL_VARCHAR;
+ // Query the data source for info about itself
+ if (!getDbInfo(failOnDataTypeUnsupported))
+ return false;
- // Float
- if (!getDataTypeInfo(SQL_DOUBLE,typeInfFloat))
- if (!getDataTypeInfo(SQL_REAL,typeInfFloat))
- if (!getDataTypeInfo(SQL_FLOAT,typeInfFloat))
- if (!getDataTypeInfo(SQL_DECIMAL,typeInfFloat))
- if (!getDataTypeInfo(SQL_NUMERIC,typeInfFloat))
- {
- if (failOnDataTypeUnsupported)
- return false;
- }
- else
- typeInfFloat.FsqlType = SQL_NUMERIC;
- else
- typeInfFloat.FsqlType = SQL_DECIMAL;
- else
- typeInfFloat.FsqlType = SQL_FLOAT;
- else
- typeInfFloat.FsqlType = SQL_REAL;
- else
- typeInfFloat.FsqlType = SQL_DOUBLE;
+ // --------------- Varchar - (Variable length character string) ---------------
+ for (iIndex = 0; iIndex < WXSIZEOF(PossibleSqlCharTypes) &&
+ !getDataTypeInfo(PossibleSqlCharTypes[iIndex], typeInfVarchar); ++iIndex)
+ {}
- // Integer
- if (!getDataTypeInfo(SQL_INTEGER, typeInfInteger))
+ if (iIndex < WXSIZEOF(PossibleSqlCharTypes))
+ typeInfVarchar.FsqlType = PossibleSqlCharTypes[iIndex];
+ else if (failOnDataTypeUnsupported)
+ return false;
+
+ // --------------- Float ---------------
+ for (iIndex = 0; iIndex < WXSIZEOF(PossibleSqlFloatTypes) &&
+ !getDataTypeInfo(PossibleSqlFloatTypes[iIndex], typeInfFloat); ++iIndex)
+ {}
+
+ if (iIndex < WXSIZEOF(PossibleSqlFloatTypes))
+ typeInfFloat.FsqlType = PossibleSqlFloatTypes[iIndex];
+ else if (failOnDataTypeUnsupported)
+ return false;
+
+ // --------------- Integer -------------
+ for (iIndex = 0; iIndex < WXSIZEOF(PossibleSqlIntegerTypes) &&
+ !getDataTypeInfo(PossibleSqlIntegerTypes[iIndex], typeInfInteger); ++iIndex)
+ {}
+
+ if (iIndex < WXSIZEOF(PossibleSqlIntegerTypes))
+ typeInfInteger.FsqlType = PossibleSqlIntegerTypes[iIndex];
+ else if (failOnDataTypeUnsupported)
{
- // If SQL_INTEGER is not supported, use the floating point
- // data type to store integers as well as floats
+ // If no non-floating point data types are supported, we'll
+ // use the type assigned for floats to store integers as well
if (!getDataTypeInfo(typeInfFloat.FsqlType, typeInfInteger))
{
if (failOnDataTypeUnsupported)
else
typeInfInteger.FsqlType = typeInfFloat.FsqlType;
}
- else
- typeInfInteger.FsqlType = SQL_INTEGER;
- // Date/Time
- if (!getDataTypeInfo(SQL_TIMESTAMP,typeInfDate))
- {
- if (!getDataTypeInfo(SQL_DATE,typeInfDate))
- {
-#ifdef SQL_DATETIME
- if (getDataTypeInfo(SQL_DATETIME,typeInfDate))
- {
- typeInfDate.FsqlType = SQL_TIME;
- }
- else
-#endif // SQL_DATETIME defined
- {
- if (failOnDataTypeUnsupported)
- return false;
- }
- }
- else
- typeInfDate.FsqlType = SQL_DATE;
- }
- else
- typeInfDate.FsqlType = SQL_TIMESTAMP;
+ // --------------- Date/Time ---------------
+ for (iIndex = 0; iIndex < WXSIZEOF(PossibleSqlDateTypes) &&
+ !getDataTypeInfo(PossibleSqlDateTypes[iIndex], typeInfDate); ++iIndex)
+ {}
+ if (iIndex < WXSIZEOF(PossibleSqlDateTypes))
+ typeInfDate.FsqlType = PossibleSqlDateTypes[iIndex];
+ else if (failOnDataTypeUnsupported)
+ return false;
- if (!getDataTypeInfo(SQL_LONGVARBINARY, typeInfBlob))
- {
- if (!getDataTypeInfo(SQL_VARBINARY,typeInfBlob))
- {
- if (failOnDataTypeUnsupported)
- return false;
- }
- else
- typeInfBlob.FsqlType = SQL_VARBINARY;
- }
- else
- typeInfBlob.FsqlType = SQL_LONGVARBINARY;
+ // --------------- BLOB ---------------
+ for (iIndex = 0; iIndex < WXSIZEOF(PossibleSqlBlobTypes) &&
+ !getDataTypeInfo(PossibleSqlBlobTypes[iIndex], typeInfBlob); ++iIndex)
+ {}
+
+ if (iIndex < WXSIZEOF(PossibleSqlBlobTypes))
+ typeInfBlob.FsqlType = PossibleSqlBlobTypes[iIndex];
+ else if (failOnDataTypeUnsupported)
+ return false;
+
+ return true;
+} // wxDb::determineDataTypes
+
+
+bool wxDb::open(bool failOnDataTypeUnsupported)
+{
+/*
+ If using Intersolv branded ODBC drivers, this is the place where you would substitute
+ your branded driver license information
+ SQLSetConnectOption(hdbc, 1041, (UDWORD) wxEmptyString);
+ SQLSetConnectOption(hdbc, 1042, (UDWORD) wxEmptyString);
+*/
+
+ // Mark database as open
+ dbIsOpen = true;
+
+ // Allocate a statement handle for the database connection
+ if (SQLAllocStmt(hdbc, &hstmt) != SQL_SUCCESS)
+ return(DispAllErrors(henv, hdbc));
+
+ // Set Connection Options
+ if (!setConnectionOptions())
+ return false;
+
+ if (!determineDataTypes(failOnDataTypeUnsupported))
+ return false;
#ifdef DBDEBUG_CONSOLE
cout << wxT("VARCHAR DATA TYPE: ") << typeInfVarchar.TypeName << endl;
{
#ifdef DBDEBUG_CONSOLE
if (retcode == SQL_NO_DATA_FOUND)
- cout << wxT("SQL_NO_DATA_FOUND fetching inf. about data type.") << endl;
+ cout << wxT("SQL_NO_DATA_FOUND fetching information about data type.") << endl;
#endif
DispAllErrors(henv, hdbc, hstmt);
SQLFreeStmt(hstmt, SQL_CLOSE);
if (++pLast == DB_MAX_ERROR_HISTORY)
{
int i;
- for (i = 0; i < DB_MAX_ERROR_HISTORY; i++)
+ for (i = 0; i < DB_MAX_ERROR_HISTORY-1; i++)
wxStrcpy(errorList[i], errorList[i+1]);
pLast--;
}
- wxStrcpy(errorList[pLast], errMsg);
+ wxStrncpy(errorList[pLast], errMsg, DB_MAX_ERROR_MSG_LEN);
+ errorList[pLast][DB_MAX_ERROR_MSG_LEN] = 0;
if (SQLState.Length())
if ((dbStatus = TranslateSqlState(SQLState)) != DB_ERR_FUNCTION_SEQUENCE_ERROR)
SDWORD Sdword;
wxDbColInf* pColInf = new wxDbColInf[noCols];
- //fill in column information (name, datatype)
+ // Fill in column information (name, datatype)
for (colNum = 0; colNum < noCols; colNum++)
{
if (SQLColAttributes(hstmt, (UWORD)(colNum+1), SQL_COLUMN_NAME,
}
wxStrncpy(pColInf[colNum].colName, name, DB_MAX_COLUMN_NAME_LEN);
+ pColInf[colNum].colName[DB_MAX_COLUMN_NAME_LEN] = 0; // Prevent buffer overrun
if (SQLColAttributes(hstmt, (UWORD)(colNum+1), SQL_COLUMN_TYPE,
NULL, 0, &Sword, &Sdword) != SQL_SUCCESS)
switch (Sdword)
{
+#if wxUSE_UNICODE
+ #if defined(SQL_WCHAR)
+ case SQL_WCHAR:
+ #endif
+ #if defined(SQL_WVARCHAR)
+ case SQL_WVARCHAR:
+ #endif
+#endif
case SQL_VARCHAR:
case SQL_CHAR:
pColInf[colNum].dbDataType = DB_DATA_TYPE_VARCHAR;
wxChar szPkTable[DB_MAX_TABLE_NAME_LEN+1]; /* Primary key table name */
wxChar szFkTable[DB_MAX_TABLE_NAME_LEN+1]; /* Foreign key table name */
SWORD iKeySeq;
-// SQLSMALLINT iKeySeq;
wxChar szPkCol[DB_MAX_COLUMN_NAME_LEN+1]; /* Primary key column */
wxChar szFkCol[DB_MAX_COLUMN_NAME_LEN+1]; /* Foreign key column */
SQLRETURN retcode;
for (i=0; i<noCols; i++)
{ // Find the Column name
if (!wxStrcmp(colInf[i].colName, szPkCol)) // We have found the Column, store the Information
- wxStrcpy(colInf[i].PkTableName, tempStr.c_str()); // Name of the Tables where this Primary Key is used as a Foreign Key
+ {
+ wxStrncpy(colInf[i].PkTableName, tempStr.c_str(), DB_MAX_TABLE_NAME_LEN); // Name of the Tables where this Primary Key is used as a Foreign Key
+ colInf[i].PkTableName[DB_MAX_TABLE_NAME_LEN] = 0; // Prevent buffer overrun
+ }
}
} // if
if (!wxStrcmp(colInf[i].colName,szFkCol)) // We have found the (Foreign Key) Column
{
colInf[i].FkCol = iKeySeq; // Which Foreign Key is this (first, second usw.) ?
- wxStrcpy(colInf[i].FkTableName,szPkTable); // Name of the Table where this Foriegn is the Primary Key
+ wxStrncpy(colInf[i].FkTableName, szFkTable, DB_MAX_TABLE_NAME_LEN); // Name of the Table where this Foriegn is the Primary Key
+ colInf[i].FkTableName[DB_MAX_TABLE_NAME_LEN] = 0; // Prevent buffer overrun
} // if
} // for
} // if
if (!colInf)
break;
// Mark the end of the array
- wxStrcpy(colInf[noCols].tableName,wxEmptyString);
- wxStrcpy(colInf[noCols].colName,wxEmptyString);
+ wxStrcpy(colInf[noCols].tableName, wxEmptyString);
+ wxStrcpy(colInf[noCols].colName, wxEmptyString);
colInf[noCols].sqlDataType = 0;
}
// Loop through each table name
// Oracle and Interbase table names are uppercase only, so force
// the name to uppercase just in case programmer forgot to do this
if ((Dbms() == dbmsORACLE) ||
+ (Dbms() == dbmsFIREBIRD) ||
(Dbms() == dbmsINTERBASE))
TableName = TableName.Upper();
// Mark the end of the array
wxStrcpy(colInf[noCols].tableName, wxEmptyString);
wxStrcpy(colInf[noCols].colName, wxEmptyString);
- colInf[noCols].sqlDataType = 0;
+ colInf[noCols].sqlDataType = 0;
}
TableName = tableName;
// Oracle and Interbase table names are uppercase only, so force
// the name to uppercase just in case programmer forgot to do this
if ((Dbms() == dbmsORACLE) ||
+ (Dbms() == dbmsFIREBIRD) ||
(Dbms() == dbmsINTERBASE))
TableName = TableName.Upper();
// Mark the end of the array
wxStrcpy(colInf[noCols].tableName, wxEmptyString);
wxStrcpy(colInf[noCols].colName, wxEmptyString);
- colInf[noCols].sqlDataType = 0;
+ colInf[noCols].sqlDataType = 0;
// Merge ...
int offset = 0;
// Oracle and Interbase table names are uppercase only, so force
// the name to uppercase just in case programmer forgot to do this
if ((Dbms() == dbmsORACLE) ||
+ (Dbms() == dbmsFIREBIRD) ||
(Dbms() == dbmsINTERBASE))
TableName = TableName.Upper();
// Get the intern datatype
switch (colInf[colNo].sqlDataType)
{
+#if wxUSE_UNICODE
+ #if defined(SQL_WCHAR)
+ case SQL_WCHAR:
+ #endif
+ #if defined(SQL_WVARCHAR)
+ case SQL_WVARCHAR:
+ #endif
+#endif
case SQL_VARCHAR:
case SQL_CHAR:
colInf[colNo].dbDataType = DB_DATA_TYPE_VARCHAR;
// Oracle and Interbase table names are uppercase only, so force
// the name to uppercase just in case programmer forgot to do this
if ((Dbms() == dbmsORACLE) ||
+ (Dbms() == dbmsFIREBIRD) ||
(Dbms() == dbmsINTERBASE))
TableName = TableName.Upper();
wxChar typeName[30+1];
SDWORD precision, length;
- FILE *fp = wxFopen(fileName.fn_str(),wxT("wt"));
+ FILE *fp = wxFopen(fileName.c_str(),wxT("wt"));
if (fp == NULL)
return false;
if (!UserID.empty() &&
Dbms() != dbmsMY_SQL &&
Dbms() != dbmsACCESS &&
+ Dbms() != dbmsFIREBIRD &&
Dbms() != dbmsINTERBASE &&
Dbms() != dbmsMS_SQL_SERVER)
{
// Oracle and Interbase table names are uppercase only, so force
// the name to uppercase just in case programmer forgot to do this
if ((Dbms() == dbmsORACLE) ||
+ (Dbms() == dbmsFIREBIRD) ||
(Dbms() == dbmsINTERBASE))
TableName = TableName.Upper();
Dbms() != dbmsACCESS &&
Dbms() != dbmsMS_SQL_SERVER &&
Dbms() != dbmsDB2 &&
+ Dbms() != dbmsFIREBIRD &&
Dbms() != dbmsINTERBASE &&
Dbms() != dbmsPERVASIVE_SQL)
{
// Oracle and Interbase table names are uppercase only, so force
// the name to uppercase just in case programmer forgot to do this
if ((Dbms() == dbmsORACLE) ||
+ (Dbms() == dbmsFIREBIRD) ||
(Dbms() == dbmsINTERBASE))
TableName = TableName.Upper();
{
if (fpSqlLog == 0)
{
- fpSqlLog = wxFopen(filename.fn_str(), (append ? wxT("at") : wxT("wt")));
+ fpSqlLog = wxFopen(filename.c_str(), (append ? wxT("at") : wxT("wt")));
if (fpSqlLog == NULL)
return false;
}
if (dbmsType != dbmsUNIDENTIFIED)
return(dbmsType);
+#ifdef DBDEBUG_CONSOLE
+ // When run in console mode, use standard out to display errors.
+ cout << "Database connecting to: " << dbInf.dbmsName << endl;
+#endif // DBDEBUG_CONSOLE
+
+ wxLogDebug(wxT("Database connecting to: "));
+ wxLogDebug(dbInf.dbmsName);
+
wxChar baseName[25+1];
- wxStrncpy(baseName,dbInf.dbmsName,25);
+ wxStrncpy(baseName, dbInf.dbmsName, 25);
baseName[25] = 0;
// RGG 20001025 : add support for Interbase
if (!wxStricmp(baseName,wxT("Informix")))
return((wxDBMS)(dbmsType = dbmsINFORMIX));
+ if (!wxStricmp(baseName,wxT("Firebird")))
+ return((wxDBMS)(dbmsType = dbmsFIREBIRD));
+
baseName[6] = 0;
if (!wxStricmp(baseName,wxT("Oracle")))
return((wxDBMS)(dbmsType = dbmsORACLE));
return((wxDBMS)(dbmsType = dbmsXBASE_SEQUITER));
if (!wxStricmp(baseName,wxT("MySQL")))
return((wxDBMS)(dbmsType = dbmsMY_SQL));
+ if (!wxStricmp(baseName,wxT("MaxDB")))
+ return((wxDBMS)(dbmsType = dbmsMAXDB));
baseName[3] = 0;
if (!wxStricmp(baseName,wxT("DB2")))
if (pDb->errorList[i])
{
msg.Append(pDb->errorList[i]);
- if (wxStrcmp(pDb->errorList[i],wxT("")) != 0)
+ if (wxStrcmp(pDb->errorList[i], wxEmptyString) != 0)
msg.Append(wxT("\n"));
// Clear the errmsg buffer so the next error will not
// end up showing the previous error that have occurred
- wxStrcpy(pDb->errorList[i],wxT(""));
+ wxStrcpy(pDb->errorList[i], wxEmptyString);
}
}
msg += wxT("\n");