- // Connect to the data source
- if (SQLConnect(hdbc, (UCHAR FAR *) Dsn, SQL_NTS,
- (UCHAR FAR *) Uid, SQL_NTS,
- (UCHAR FAR *) AuthStr, SQL_NTS) != SQL_SUCCESS)
- return(DispAllErrors(henv, hdbc));
-
- // 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);
-
- // Query the data source for inf. about itself
- if (! getDbInfo())
- return(FALSE);
-
- // Query the data source regarding data type information
-
- //
- // The way I determined which SQL data types to use was by calling SQLGetInfo
- // 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
- // 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_BIGINT SQL_NO_DATA_FOUND
- // SQL_BINARY SQL_NO_DATA_FOUND
- // SQL_BIT SQL_NO_DATA_FOUND
- // SQL_CHAR type name = 'CHAR', Precision = 255
- // SQL_DATE SQL_NO_DATA_FOUND
- // SQL_DECIMAL type name = 'NUMBER', Precision = 38
- // SQL_DOUBLE type name = 'NUMBER', Precision = 15
- // SQL_FLOAT SQL_NO_DATA_FOUND
- // SQL_INTEGER SQL_NO_DATA_FOUND
- // SQL_LONGVARBINARY type name = 'LONG RAW', Precision = 2 billion
- // SQL_LONGVARCHAR type name = 'LONG', Precision = 2 billion
- // SQL_NUMERIC SQL_NO_DATA_FOUND
- // SQL_REAL SQL_NO_DATA_FOUND
- // SQL_SMALLINT SQL_NO_DATA_FOUND
- // SQL_TIME SQL_NO_DATA_FOUND
- // SQL_TIMESTAMP type name = 'DATE', Precision = 19
- // SQL_VARBINARY type name = 'RAW', Precision = 255
- // SQL_VARCHAR type name = 'VARCHAR2', Precision = 2000
- // =====================================================================
- // Results from a Microsoft Access 7.0 db, using a driver from Microsoft
- //
- // SQL_VARCHAR type name = 'TEXT(', Precision = 255
- // SQL_TIMESTAMP type name = 'DATETIME'
- // SQL_DECIMAL SQL_NO_DATA_FOUND
- // SQL_NUMERIC type name = 'CURRENCY', Precision = 19
- // SQL_FLOAT SQL_NO_DATA_FOUND
- // SQL_REAL type name = 'SINGLE', Precision = 7
- // 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;
-
- // 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))
- 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;
-
- // Integer
- if (! getDataTypeInfo(SQL_INTEGER, typeInfInteger))
- // If SQL_INTEGER is not supported, use the floating point
- // data type to store integers as well as floats
- if (! getDataTypeInfo(typeInfFloat.FsqlType, typeInfInteger))
- return(FALSE);
- else
- typeInfInteger.FsqlType = typeInfFloat.FsqlType;
- else
- typeInfInteger.FsqlType = SQL_INTEGER;
-
- // Date/Time
- if (! getDataTypeInfo(SQL_TIMESTAMP, typeInfDate))
- return(FALSE);
- else
- typeInfDate.FsqlType = SQL_TIMESTAMP;
+// SQL Log defaults to be used by GetDbConnection
+wxDbSqlLogState SQLLOGstate = sqlLogOFF;
+
+static wxString SQLLOGfn = SQL_LOG_FILENAME;
+
+// The wxDb::errorList is copied to this variable when the wxDb object
+// is closed. This way, the error list is still available after the
+// database object is closed. This is necessary if the database
+// connection fails so the calling application can show the operator
+// why the connection failed. Note: as each wxDb object is closed, it
+// 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];
+
+
+// This type defines the return row-struct form
+// SQLTablePrivileges, and is used by wxDB::TablePrivileges.
+typedef struct
+{
+ wxChar tableQual[128+1];
+ wxChar tableOwner[128+1];
+ wxChar tableName[128+1];
+ wxChar grantor[128+1];
+ wxChar grantee[128+1];
+ wxChar privilege[128+1];
+ wxChar grantable[3+1];
+} wxDbTablePrivilegeInfo;
+
+
+/********** wxDbConnectInf Constructor - form 1 **********/
+wxDbConnectInf::wxDbConnectInf()
+{
+ Henv = 0;
+ freeHenvOnDestroy = FALSE;
+
+ Initialize();
+} // Constructor
+
+
+/********** wxDbConnectInf Constructor - form 2 **********/
+wxDbConnectInf::wxDbConnectInf(HENV henv, const wxString &dsn, const wxString &userID,
+ const wxString &password, const wxString &defaultDir,
+ const wxString &fileType, const wxString &description)
+{
+ Henv = 0;
+ freeHenvOnDestroy = FALSE;
+
+ Initialize();
+
+ if (henv)
+ SetHenv(henv);
+ else
+ AllocHenv();
+
+ SetDsn(dsn);
+ SetUserID(userID);
+ SetPassword(password);
+ SetDescription(description);
+ SetFileType(fileType);
+ SetDefaultDir(defaultDir);
+} // wxDbConnectInf Constructor
+
+
+wxDbConnectInf::~wxDbConnectInf()
+{
+ if (freeHenvOnDestroy)
+ {
+ FreeHenv();
+ }
+} // wxDbConnectInf Destructor
+
+
+
+/********** wxDbConnectInf::Initialize() **********/
+bool wxDbConnectInf::Initialize()
+{
+ freeHenvOnDestroy = FALSE;
+
+ if (freeHenvOnDestroy && Henv)
+ FreeHenv();
+
+ Henv = 0;
+ Dsn[0] = 0;
+ Uid[0] = 0;
+ AuthStr[0] = 0;
+ ConnectionStr[0] = 0;
+ Description.Empty();
+ FileType.Empty();
+ DefaultDir.Empty();
+
+ useConnectionStr = FALSE;
+
+ return TRUE;
+} // wxDbConnectInf::Initialize()
+
+
+/********** wxDbConnectInf::AllocHenv() **********/
+bool wxDbConnectInf::AllocHenv()
+{
+ // This is here to help trap if you are getting a new henv
+ // without releasing an existing henv
+ wxASSERT(!Henv);
+
+ // Initialize the ODBC Environment for Database Operations
+ if (SQLAllocEnv(&Henv) != SQL_SUCCESS)
+ {
+ wxLogDebug(wxT("A problem occured while trying to get a connection to the data source"));
+ return FALSE;
+ }
+
+ freeHenvOnDestroy = TRUE;
+
+ return TRUE;
+} // wxDbConnectInf::AllocHenv()
+
+
+void wxDbConnectInf::FreeHenv()
+{
+ wxASSERT(Henv);
+
+ if (Henv)
+ SQLFreeEnv(Henv);
+
+ Henv = 0;
+ freeHenvOnDestroy = FALSE;
+
+} // wxDbConnectInf::FreeHenv()
+
+
+void wxDbConnectInf::SetDsn(const wxString &dsn)
+{
+ wxASSERT(dsn.Length() < sizeof(Dsn));
+
+ wxStrcpy(Dsn,dsn);
+} // wxDbConnectInf::SetDsn()
+
+
+void wxDbConnectInf::SetUserID(const wxString &uid)
+{
+ wxASSERT(uid.Length() < sizeof(Uid));
+ wxStrcpy(Uid, uid);
+} // wxDbConnectInf::SetUserID()
+
+
+void wxDbConnectInf::SetPassword(const wxString &password)
+{
+ wxASSERT(password.Length() < sizeof(AuthStr));
+
+ wxStrcpy(AuthStr, password);
+} // wxDbConnectInf::SetPassword()
+
+void wxDbConnectInf::SetConnectionStr(const wxString &connectStr)
+{
+ wxASSERT(connectStr.Length() < sizeof(ConnectionStr));
+
+ useConnectionStr = wxStrlen(connectStr) > 0;
+
+ wxStrcpy(ConnectionStr, connectStr);
+} // wxDbConnectInf::SetConnectionStr()
+
+
+/********** wxDbColFor Constructor **********/
+wxDbColFor::wxDbColFor()
+{
+ Initialize();
+} // wxDbColFor::wxDbColFor()
+
+
+wxDbColFor::~wxDbColFor()
+{
+} // wxDbColFor::~wxDbColFor()
+
+
+/********** wxDbColFor::Initialize() **********/
+void wxDbColFor::Initialize()
+{
+ s_Field.Empty();
+ int i;
+ for (i=0; i<7; i++)
+ {
+ s_Format[i].Empty();
+ s_Amount[i].Empty();
+ i_Amount[i] = 0;
+ }
+ i_Nation = 0; // 0=EU, 1=UK, 2=International, 3=US
+ i_dbDataType = 0;
+ i_sqlDataType = 0;
+ Format(1,DB_DATA_TYPE_VARCHAR,0,0,0); // the Function that does the work
+} // wxDbColFor::Initialize()
+
+
+/********** wxDbColFor::Format() **********/
+int wxDbColFor::Format(int Nation, int dbDataType, SWORD sqlDataType,
+ short columnSize, short decimalDigits)
+{
+ // ----------------------------------------------------------------------------------------
+ // -- 19991224 : mj10777 : Create
+ // There is still a lot of work to do here, but it is a start
+ // It handles all the basic data-types that I have run into up to now
+ // The main work will have be with Dates and float Formatting
+ // (US 1,000.00 ; EU 1.000,00)
+ // There are wxWindow plans for locale support and the new wxDateTime. If
+ // they define some constants (wxEUROPEAN) that can be gloably used,
+ // they should be used here.
+ // ----------------------------------------------------------------------------------------
+ // There should also be a function to scan in a string to fill the variable
+ // ----------------------------------------------------------------------------------------
+ wxString tempStr;
+ i_Nation = Nation; // 0 = timestamp , 1=EU, 2=UK, 3=International, 4=US
+ i_dbDataType = dbDataType;
+ i_sqlDataType = sqlDataType;
+ s_Field.Printf(wxT("%s%d"),s_Amount[1].c_str(),i_Amount[1]); // OK for VARCHAR, INTEGER and FLOAT
+
+ if (i_dbDataType == 0) // Filter unsupported dbDataTypes
+ {
+ if ((i_sqlDataType == SQL_VARCHAR) || (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;
+ if (i_sqlDataType == SQL_REAL)
+ i_dbDataType = DB_DATA_TYPE_FLOAT;
+ if (i_sqlDataType == SQL_C_BINARY)
+ i_dbDataType = DB_DATA_TYPE_BLOB;
+ }
+
+ if ((i_dbDataType == DB_DATA_TYPE_INTEGER) && (i_sqlDataType == SQL_C_DOUBLE))
+ { // DBASE Numeric
+ i_dbDataType = DB_DATA_TYPE_FLOAT;
+ }
+
+ switch(i_dbDataType) // TBD: Still a lot of proper formatting to do
+ {
+ case DB_DATA_TYPE_VARCHAR:
+ s_Field = wxT("%s");
+ break;
+ case DB_DATA_TYPE_INTEGER:
+ s_Field = wxT("%d");
+ break;
+ case DB_DATA_TYPE_FLOAT:
+ if (decimalDigits == 0)
+ decimalDigits = 2;
+ tempStr = wxT("%");
+ tempStr.Printf(wxT("%s%d.%d"),tempStr.c_str(),columnSize,decimalDigits);
+ s_Field.Printf(wxT("%sf"),tempStr.c_str());
+ break;
+ case DB_DATA_TYPE_DATE:
+ if (i_Nation == 0) // timestamp YYYY-MM-DD HH:MM:SS.SSS (tested for SYBASE)
+ {
+ s_Field = wxT("%04d-%02d-%02d %02d:%02d:%02d.%03d");
+ }
+ if (i_Nation == 1) // European DD.MM.YYYY HH:MM:SS.SSS
+ {
+ s_Field = wxT("%02d.%02d.%04d %02d:%02d:%02d.%03d");
+ }
+ if (i_Nation == 2) // UK DD/MM/YYYY HH:MM:SS.SSS
+ {
+ s_Field = wxT("%02d/%02d/%04d %02d:%02d:%02d.%03d");
+ }
+ if (i_Nation == 3) // International YYYY-MM-DD HH:MM:SS.SSS
+ {
+ s_Field = wxT("%04d-%02d-%02d %02d:%02d:%02d.%03d");
+ }
+ if (i_Nation == 4) // US MM/DD/YYYY HH:MM:SS.SSS
+ {
+ s_Field = wxT("%02d/%02d/%04d %02d:%02d:%02d.%03d");
+ }
+ break;
+ case DB_DATA_TYPE_BLOB:
+ s_Field.Printf(wxT("Unable to format(%d)-SQL(%d)"),dbDataType,sqlDataType); //
+ break;
+ default:
+ s_Field.Printf(wxT("Unknown Format(%d)-SQL(%d)"),dbDataType,sqlDataType); //
+ break;
+ };
+ return TRUE;
+} // wxDbColFor::Format()
+
+
+
+/********** wxDbColInf Constructor **********/
+wxDbColInf::wxDbColInf()
+{
+ Initialize();
+} // wxDbColInf::wxDbColInf()
+
+
+/********** wxDbColInf Destructor ********/
+wxDbColInf::~wxDbColInf()
+{
+ if (pColFor)
+ delete pColFor;
+ pColFor = NULL;
+} // wxDbColInf::~wxDbColInf()
+
+
+bool wxDbColInf::Initialize()
+{
+ catalog[0] = 0;
+ schema[0] = 0;
+ tableName[0] = 0;
+ colName[0] = 0;
+ sqlDataType = 0;
+ typeName[0] = 0;
+ columnSize = 0;
+ bufferLength = 0;
+ decimalDigits = 0;
+ numPrecRadix = 0;
+ nullable = 0;
+ remarks[0] = 0;
+ dbDataType = 0;
+ PkCol = 0;
+ PkTableName[0] = 0;
+ FkCol = 0;
+ FkTableName[0] = 0;
+ pColFor = NULL;
+
+ return TRUE;
+} // wxDbColInf::Initialize()
+
+
+/********** wxDbTableInf Constructor ********/
+wxDbTableInf::wxDbTableInf()
+{
+ Initialize();
+} // wxDbTableInf::wxDbTableInf()
+
+
+/********** wxDbTableInf Constructor ********/
+wxDbTableInf::~wxDbTableInf()
+{
+ if (pColInf)
+ delete [] pColInf;
+ pColInf = NULL;
+} // wxDbTableInf::~wxDbTableInf()
+
+
+bool wxDbTableInf::Initialize()
+{
+ tableName[0] = 0;
+ tableType[0] = 0;
+ tableRemarks[0] = 0;
+ numCols = 0;
+ pColInf = NULL;
+
+ return TRUE;
+} // wxDbTableInf::Initialize()
+
+
+/********** wxDbInf Constructor *************/
+wxDbInf::wxDbInf()
+{
+ Initialize();
+} // wxDbInf::wxDbInf()
+
+
+/********** wxDbInf Destructor *************/
+wxDbInf::~wxDbInf()
+{
+ if (pTableInf)
+ delete [] pTableInf;
+ pTableInf = NULL;
+} // wxDbInf::~wxDbInf()
+
+
+/********** wxDbInf::Initialize() *************/
+bool wxDbInf::Initialize()
+{
+ catalog[0] = 0;
+ schema[0] = 0;
+ numTables = 0;
+ pTableInf = NULL;
+
+ return TRUE;
+} // wxDbInf::Initialize()
+
+
+/********** wxDb Constructor **********/
+wxDb::wxDb(const HENV &aHenv, bool FwdOnlyCursors)
+{
+ // Copy the HENV into the db class
+ henv = aHenv;
+ fwdOnlyCursors = FwdOnlyCursors;
+
+ initialize();
+} // wxDb::wxDb()
+
+
+/********** wxDb Destructor **********/
+wxDb::~wxDb()
+{
+ wxASSERT_MSG(!IsCached(),wxT("Cached connections must not be manually deleted, use\nwxDbFreeConnection() or wxDbCloseConnections()."));
+
+ if (IsOpen())
+ {
+ Close();
+ }
+} // wxDb destructor
+
+
+
+/********** PRIVATE! wxDb::initialize PRIVATE! **********/
+/********** wxDb::initialize() **********/
+void wxDb::initialize()
+/*
+ * Private member function that sets all wxDb member variables to
+ * known values at creation of the wxDb
+ */
+{
+ int i;
+
+ fpSqlLog = 0; // Sql Log file pointer
+ sqlLogState = sqlLogOFF; // By default, logging is turned off
+ nTables = 0;
+ dbmsType = dbmsUNIDENTIFIED;
+
+ wxStrcpy(sqlState,wxEmptyString);
+ wxStrcpy(errorMsg,wxEmptyString);
+ nativeError = cbErrorMsg = 0;
+ for (i = 0; i < DB_MAX_ERROR_HISTORY; i++)
+ wxStrcpy(errorList[i], wxEmptyString);
+
+ // Init typeInf structures
+ typeInfVarchar.TypeName.Empty();
+ typeInfVarchar.FsqlType = 0;
+ typeInfVarchar.Precision = 0;
+ typeInfVarchar.CaseSensitive = 0;
+ typeInfVarchar.MaximumScale = 0;
+
+ typeInfInteger.TypeName.Empty();
+ typeInfInteger.FsqlType = 0;
+ typeInfInteger.Precision = 0;
+ typeInfInteger.CaseSensitive = 0;
+ typeInfInteger.MaximumScale = 0;
+
+ typeInfFloat.TypeName.Empty();
+ typeInfFloat.FsqlType = 0;
+ typeInfFloat.Precision = 0;
+ typeInfFloat.CaseSensitive = 0;
+ typeInfFloat.MaximumScale = 0;
+
+ typeInfDate.TypeName.Empty();
+ typeInfDate.FsqlType = 0;
+ typeInfDate.Precision = 0;
+ typeInfDate.CaseSensitive = 0;
+ typeInfDate.MaximumScale = 0;
+
+ typeInfBlob.TypeName.Empty();
+ typeInfBlob.FsqlType = 0;
+ typeInfBlob.Precision = 0;
+ typeInfBlob.CaseSensitive = 0;
+ typeInfBlob.MaximumScale = 0;
+
+ // Error reporting is turned OFF by default
+ silent = TRUE;
+
+ // Allocate a data source connection handle
+ if (SQLAllocConnect(henv, &hdbc) != SQL_SUCCESS)
+ DispAllErrors(henv);
+
+ // Initialize the db status flag
+ DB_STATUS = 0;
+
+ // Mark database as not open as of yet
+ dbIsOpen = FALSE;
+ dbIsCached = FALSE;
+ dbOpenedWithConnectionString = FALSE;
+} // wxDb::initialize()
+
+
+/********** PRIVATE! wxDb::convertUserID PRIVATE! **********/
+//
+// NOTE: Return value from this function MUST be copied
+// immediately, as the value is not good after
+// this function has left scope.
+//
+const wxChar *wxDb::convertUserID(const wxChar *userID, wxString &UserID)
+{
+ if (userID)
+ {
+ if (!wxStrlen(userID))
+ UserID = uid;
+ else
+ UserID = userID;
+ }
+ else
+ UserID.Empty();
+
+ // dBase does not use user names, and some drivers fail if you try to pass one
+ if ( Dbms() == dbmsDBASE
+ || Dbms() == dbmsXBASE_SEQUITER )
+ UserID.Empty();
+
+ // Oracle user names may only be in uppercase, so force
+ // the name to uppercase
+ if (Dbms() == dbmsORACLE)
+ UserID = UserID.Upper();
+
+ return UserID.c_str();
+} // wxDb::convertUserID()
+
+
+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);
+
+ // Query the data source for inf. about itself
+ if (!getDbInfo(failOnDataTypeUnsupported))
+ return(FALSE);
+
+ // Query the data source regarding data type information
+
+ //
+ // The way it was determined which SQL data types to use was by calling SQLGetInfo
+ // 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
+ // 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_BIGINT SQL_NO_DATA_FOUND
+ // SQL_BINARY SQL_NO_DATA_FOUND
+ // SQL_BIT SQL_NO_DATA_FOUND
+ // SQL_CHAR type name = 'CHAR', Precision = 255
+ // SQL_DATE SQL_NO_DATA_FOUND
+ // SQL_DECIMAL type name = 'NUMBER', Precision = 38
+ // SQL_DOUBLE type name = 'NUMBER', Precision = 15
+ // SQL_FLOAT SQL_NO_DATA_FOUND
+ // SQL_INTEGER SQL_NO_DATA_FOUND
+ // SQL_LONGVARBINARY type name = 'LONG RAW', Precision = 2 billion
+ // SQL_LONGVARCHAR type name = 'LONG', Precision = 2 billion
+ // SQL_NUMERIC SQL_NO_DATA_FOUND
+ // SQL_REAL SQL_NO_DATA_FOUND
+ // SQL_SMALLINT SQL_NO_DATA_FOUND
+ // SQL_TIME SQL_NO_DATA_FOUND
+ // SQL_TIMESTAMP type name = 'DATE', Precision = 19
+ // SQL_VARBINARY type name = 'RAW', Precision = 255
+ // SQL_VARCHAR type name = 'VARCHAR2', Precision = 2000
+ // =====================================================================
+ // Results from a Microsoft Access 7.0 db, using a driver from Microsoft
+ //
+ // SQL_VARCHAR type name = 'TEXT', Precision = 255
+ // SQL_TIMESTAMP type name = 'DATETIME'
+ // SQL_DECIMAL SQL_NO_DATA_FOUND
+ // SQL_NUMERIC type name = 'CURRENCY', Precision = 19
+ // SQL_FLOAT SQL_NO_DATA_FOUND
+ // SQL_REAL type name = 'SINGLE', Precision = 7
+ // 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;
+
+ // 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;
+
+ // Integer
+ if (!getDataTypeInfo(SQL_INTEGER, typeInfInteger))
+ {
+ // If SQL_INTEGER is not supported, use the floating point
+ // data type to store integers as well as floats
+ if (!getDataTypeInfo(typeInfFloat.FsqlType, typeInfInteger))
+ {
+ if (failOnDataTypeUnsupported)
+ return(FALSE);
+ }
+ 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;
+
+
+ if (!getDataTypeInfo(SQL_LONGVARBINARY, typeInfBlob))
+ {
+ if (!getDataTypeInfo(SQL_VARBINARY,typeInfBlob))
+ {
+ if (failOnDataTypeUnsupported)
+ return(FALSE);
+ }
+ else
+ typeInfBlob.FsqlType = SQL_VARBINARY;
+ }
+ else
+ typeInfBlob.FsqlType = SQL_LONGVARBINARY;
+