// Purpose: Implementation of the wxDb class. The wxDb class represents a connection
// to an ODBC data source. The wxDb class allows operations on the data
// source such as opening and closing the data source.
// Purpose: Implementation of the wxDb class. The wxDb class represents a connection
// to an ODBC data source. The wxDb class allows operations on the data
// source such as opening and closing the data source.
// Licence: wxWindows licence
///////////////////////////////////////////////////////////////////////////////
// Licence: wxWindows licence
///////////////////////////////////////////////////////////////////////////////
- wxStrncpy(Dsn, dsn, sizeof(Dsn)-1);
- Dsn[sizeof(Dsn)-1] = 0; // Prevent buffer overrun
+ wxStrncpy(Dsn, dsn, WXSIZEOF(Dsn)-1);
+ Dsn[WXSIZEOF(Dsn)-1] = 0; // Prevent buffer overrun
- wxASSERT(uid.Length() < sizeof(Uid));
- wxStrncpy(Uid, uid, sizeof(Uid)-1);
- Uid[sizeof(Uid)-1] = 0; // Prevent buffer overrun
+ wxASSERT(uid.length() < WXSIZEOF(Uid));
+ wxStrncpy(Uid, uid, WXSIZEOF(Uid)-1);
+ Uid[WXSIZEOF(Uid)-1] = 0; // Prevent buffer overrun
- wxStrncpy(AuthStr, password, sizeof(AuthStr)-1);
- AuthStr[sizeof(AuthStr)-1] = 0; // Prevent buffer overrun
+ wxStrncpy(AuthStr, password, WXSIZEOF(AuthStr)-1);
+ AuthStr[WXSIZEOF(AuthStr)-1] = 0; // Prevent buffer overrun
- wxStrncpy(ConnectionStr, connectStr, sizeof(ConnectionStr)-1);
- ConnectionStr[sizeof(ConnectionStr)-1] = 0; // Prevent buffer overrun
+ wxStrncpy(ConnectionStr, connectStr, WXSIZEOF(ConnectionStr)-1);
+ ConnectionStr[WXSIZEOF(ConnectionStr)-1] = 0; // Prevent buffer overrun
- tempStr = wxT("%");
- tempStr.Printf(wxT("%s%d.%d"), tempStr.c_str(),columnLength, decimalDigits);
+ tempStr.Printf(wxT("%%%d.%d"), columnLength, decimalDigits);
+ typeInfMemo.TypeName.Empty();
+ typeInfMemo.FsqlType = 0;
+ typeInfMemo.Precision = 0;
+ typeInfMemo.CaseSensitive = 0;
+ typeInfMemo.MaximumScale = 0;
+
+ // 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 MEMO column types
+ // (a type which allow to store large strings; like VARCHAR just with a bigger precision)
+ //
+ // 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 PossibleSqlMemoTypes[] = {
+ SQL_LONGVARCHAR,
+ };
+
+ // --------------- MEMO ---------------
+ for (iIndex = 0; iIndex < WXSIZEOF(PossibleSqlMemoTypes) &&
+ !getDataTypeInfo(PossibleSqlMemoTypes[iIndex], typeInfMemo); ++iIndex)
+ {}
+
+ if (iIndex < WXSIZEOF(PossibleSqlMemoTypes))
+ typeInfMemo.FsqlType = PossibleSqlMemoTypes[iIndex];
+ else if (failOnDataTypeUnsupported)
+ return false;
+
cout << wxT("FLOAT DATA TYPE: ") << typeInfFloat.TypeName << endl;
cout << wxT("DATE DATA TYPE: ") << typeInfDate.TypeName << endl;
cout << wxT("BLOB DATA TYPE: ") << typeInfBlob.TypeName << endl;
cout << wxT("FLOAT DATA TYPE: ") << typeInfFloat.TypeName << endl;
cout << wxT("DATE DATA TYPE: ") << typeInfDate.TypeName << endl;
cout << wxT("BLOB DATA TYPE: ") << typeInfBlob.TypeName << endl;
- wxASSERT(inConnectStr.Length());
- dsn = wxT("");
- uid = wxT("");
- authStr = wxT("");
+ wxASSERT(inConnectStr.length());
+ return Open(inConnectStr, NULL, failOnDataTypeUnsupported);
+}
+
+bool wxDb::Open(const wxString& inConnectStr, SQLHWND parentWnd, bool failOnDataTypeUnsupported)
+{
+ dsn = wxEmptyString;
+ uid = wxEmptyString;
+ authStr = wxEmptyString;
- retcode = SQLDriverConnect(hdbc, NULL, (SQLTCHAR FAR *)inConnectionStr.c_str(),
- (SWORD)inConnectionStr.Length(), (SQLTCHAR FAR *)outConnectBuffer,
- sizeof(outConnectBuffer), &outConnectBufferLen, SQL_DRIVER_COMPLETE );
+ retcode = SQLDriverConnect(hdbc, parentWnd, (SQLTCHAR FAR *)inConnectionStr.c_str(),
+ (SWORD)inConnectionStr.length(), (SQLTCHAR FAR *)outConnectBuffer,
+ WXSIZEOF(outConnectBuffer), &outConnectBufferLen, SQL_DRIVER_COMPLETE );
/********** wxDb::Open() **********/
bool wxDb::Open(const wxString &Dsn, const wxString &Uid, const wxString &AuthStr, bool failOnDataTypeUnsupported)
{
/********** wxDb::Open() **********/
bool wxDb::Open(const wxString &Dsn, const wxString &Uid, const wxString &AuthStr, bool failOnDataTypeUnsupported)
{
else
return Open(dbConnectInf->GetDsn(), dbConnectInf->GetUserID(),
dbConnectInf->GetPassword(), failOnDataTypeUnsupported);
else
return Open(dbConnectInf->GetDsn(), dbConnectInf->GetUserID(),
dbConnectInf->GetPassword(), failOnDataTypeUnsupported);
inConnectionStr = copyDb->GetConnectionInStr();
retcode = SQLDriverConnect(hdbc, NULL, (SQLTCHAR FAR *)inConnectionStr.c_str(),
inConnectionStr = copyDb->GetConnectionInStr();
retcode = SQLDriverConnect(hdbc, NULL, (SQLTCHAR FAR *)inConnectionStr.c_str(),
- (SWORD)inConnectionStr.Length(), (SQLTCHAR FAR *)outConnectBuffer,
- sizeof(outConnectBuffer), &outConnectBufferLen, SQL_DRIVER_COMPLETE);
+ (SWORD)inConnectionStr.length(), (SQLTCHAR FAR *)outConnectBuffer,
+ WXSIZEOF(outConnectBuffer), &outConnectBufferLen, SQL_DRIVER_COMPLETE);
typeInfBlob.CaseSensitive = copyDb->typeInfBlob.CaseSensitive;
typeInfBlob.MaximumScale = copyDb->typeInfBlob.MaximumScale;
typeInfBlob.CaseSensitive = copyDb->typeInfBlob.CaseSensitive;
typeInfBlob.MaximumScale = copyDb->typeInfBlob.MaximumScale;
+ // Memo
+ typeInfMemo.FsqlType = copyDb->typeInfMemo.FsqlType;
+ typeInfMemo.TypeName = copyDb->typeInfMemo.TypeName;
+ typeInfMemo.Precision = copyDb->typeInfMemo.Precision;
+ typeInfMemo.CaseSensitive = copyDb->typeInfMemo.CaseSensitive;
+ typeInfMemo.MaximumScale = copyDb->typeInfMemo.MaximumScale;
+
#ifdef DBDEBUG_CONSOLE
cout << wxT("VARCHAR DATA TYPE: ") << typeInfVarchar.TypeName << endl;
cout << wxT("INTEGER DATA TYPE: ") << typeInfInteger.TypeName << endl;
cout << wxT("FLOAT DATA TYPE: ") << typeInfFloat.TypeName << endl;
cout << wxT("DATE DATA TYPE: ") << typeInfDate.TypeName << endl;
cout << wxT("BLOB DATA TYPE: ") << typeInfBlob.TypeName << endl;
#ifdef DBDEBUG_CONSOLE
cout << wxT("VARCHAR DATA TYPE: ") << typeInfVarchar.TypeName << endl;
cout << wxT("INTEGER DATA TYPE: ") << typeInfInteger.TypeName << endl;
cout << wxT("FLOAT DATA TYPE: ") << typeInfFloat.TypeName << endl;
cout << wxT("DATE DATA TYPE: ") << typeInfDate.TypeName << endl;
cout << wxT("BLOB DATA TYPE: ") << typeInfBlob.TypeName << endl;
// Get information about the data type specified
if (SQLGetTypeInfo(hstmt, fSqlType) != SQL_SUCCESS)
// Get information about the data type specified
if (SQLGetTypeInfo(hstmt, fSqlType) != SQL_SUCCESS)
- s.Printf(wxT("(%-20s) tableID:[%6lu] pDb:[%p]"), tiu->tableName,tiu->tableID,tiu->pDb);
- s2.Printf(wxT("Orphaned table found using pDb:[%p]"),this);
+ s.Printf(wxT("(%-20s) tableID:[%6lu] pDb:[%p]"),
+ tiu->tableName, tiu->tableID, wx_static_cast(void*, tiu->pDb));
+ s2.Printf(wxT("Orphaned table found using pDb:[%p]"), wx_static_cast(void*, this));
wxLogDebug(s.c_str(),s2.c_str());
}
pNode = pNode->GetNext();
wxLogDebug(s.c_str(),s2.c_str());
}
pNode = pNode->GetNext();
/*
* This function is called internally whenever an error condition prevents the user's
* request from being executed. This function will query the datasource as to the
/*
* This function is called internally whenever an error condition prevents the user's
* request from being executed. This function will query the datasource as to the
*
* The function will retrieve each error condition from the datasource and
* Printf the codes/text values into a string which it then logs via logError().
* If in DBDEBUG_CONSOLE mode, the constructed string will be displayed in the console
* window and program execution will be paused until the user presses a key.
*
*
* The function will retrieve each error condition from the datasource and
* Printf the codes/text values into a string which it then logs via logError().
* If in DBDEBUG_CONSOLE mode, the constructed string will be displayed in the console
* window and program execution will be paused until the user presses a key.
*
/********** wxDb::logError() **********/
void wxDb::logError(const wxString &errMsg, const wxString &SQLState)
{
/********** wxDb::logError() **********/
void wxDb::logError(const wxString &errMsg, const wxString &SQLState)
{
wxStrncpy(errorList[pLast], errMsg, DB_MAX_ERROR_MSG_LEN);
errorList[pLast][DB_MAX_ERROR_MSG_LEN] = 0;
wxStrncpy(errorList[pLast], errMsg, DB_MAX_ERROR_MSG_LEN);
errorList[pLast][DB_MAX_ERROR_MSG_LEN] = 0;
wxDbColInf* pColInf = new wxDbColInf[noCols];
// Fill in column information (name, datatype)
wxDbColInf* pColInf = new wxDbColInf[noCols];
// Fill in column information (name, datatype)
{
if (SQLColAttributes(hstmt, (UWORD)(colNum+1), SQL_COLUMN_NAME,
name, sizeof(name),
{
if (SQLColAttributes(hstmt, (UWORD)(colNum+1), SQL_COLUMN_NAME,
name, sizeof(name),
pColInf[colNum].colName[DB_MAX_COLUMN_NAME_LEN] = 0; // Prevent buffer overrun
if (SQLColAttributes(hstmt, (UWORD)(colNum+1), SQL_COLUMN_TYPE,
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)
+ NULL, 0, &Sword, &Sqllen) != SQL_SUCCESS)
-bool wxDb::GetData(UWORD colNo, SWORD cType, PTR pData, SDWORD maxLen, SDWORD FAR *cbReturned)
+bool wxDb::GetData(UWORD colNo, SWORD cType, PTR pData, SDWORD maxLen, SQLLEN FAR *cbReturned)
wxChar szPkCol[DB_MAX_COLUMN_NAME_LEN+1]; /* Primary key column */
wxChar szFkCol[DB_MAX_COLUMN_NAME_LEN+1]; /* Foreign key column */
SQLRETURN retcode;
wxChar szPkCol[DB_MAX_COLUMN_NAME_LEN+1]; /* Primary key column */
wxChar szFkCol[DB_MAX_COLUMN_NAME_LEN+1]; /* Foreign key column */
SQLRETURN retcode;
GetData( 5, SQL_C_SSHORT, &iKeySeq, 0, &cb);
GetData( 7, SQL_C_WXCHAR, szFkTable, DB_MAX_TABLE_NAME_LEN+1, &cb);
GetData( 8, SQL_C_WXCHAR, szFkCol, DB_MAX_COLUMN_NAME_LEN+1, &cb);
GetData( 5, SQL_C_SSHORT, &iKeySeq, 0, &cb);
GetData( 7, SQL_C_WXCHAR, szFkTable, DB_MAX_TABLE_NAME_LEN+1, &cb);
GetData( 8, SQL_C_WXCHAR, szFkCol, DB_MAX_COLUMN_NAME_LEN+1, &cb);
* 1) The last array element of the tableName[] argument must be zero (null).
* This is how the end of the array is detected.
* 2) This function returns an array of wxDbColInf structures. If no columns
* 1) The last array element of the tableName[] argument must be zero (null).
* This is how the end of the array is detected.
* 2) This function returns an array of wxDbColInf structures. If no columns
* CALLING FUNCTION IS RESPONSIBLE FOR DELETING THE MEMORY RETURNED WHEN IT
* IS FINISHED WITH IT. i.e.
*
* CALLING FUNCTION IS RESPONSIBLE FOR DELETING THE MEMORY RETURNED WHEN IT
* IS FINISHED WITH IT. i.e.
*
DispAllErrors(henv, hdbc, hstmt);
SQLFreeStmt(hstmt, SQL_CLOSE);
return(-1);
DispAllErrors(henv, hdbc, hstmt);
SQLFreeStmt(hstmt, SQL_CLOSE);
return(-1);
DispAllErrors(henv, hdbc, hstmt);
SQLFreeStmt(hstmt, SQL_CLOSE);
return(-1);
DispAllErrors(henv, hdbc, hstmt);
SQLFreeStmt(hstmt, SQL_CLOSE);
return(-1);
* -- : uses SQLTables and fills pTableInf; ------
* -- : pColInf is set to NULL and numCols to 0; ------
* -- : returns pDbInf (wxDbInf) ------
* -- : uses SQLTables and fills pTableInf; ------
* -- : pColInf is set to NULL and numCols to 0; ------
* -- : returns pDbInf (wxDbInf) ------
* -- : pColInf can be filled with GetColumns(..); ------
* -- : numCols can be filled with GetColumnCount(..); ------
* ---------------------------------------------------------------------
* -- : pColInf can be filled with GetColumns(..); ------
* -- : numCols can be filled with GetColumnCount(..); ------
* ---------------------------------------------------------------------
dbName.Printf(wxT("%s/%s.dbf"), tablePath.c_str(), tableName.c_str());
else
dbName.Printf(wxT("%s.dbf"), tableName.c_str());
dbName.Printf(wxT("%s/%s.dbf"), tablePath.c_str(), tableName.c_str());
else
dbName.Printf(wxT("%s.dbf"), tableName.c_str());
bool wxDb::TablePrivileges(const wxString &tableName, const wxString &priv, const wxChar *userID,
const wxChar *schema, const wxString &WXUNUSED(tablePath))
{
bool wxDb::TablePrivileges(const wxString &tableName, const wxString &priv, const wxChar *userID,
const wxChar *schema, const wxString &WXUNUSED(tablePath))
{
bool wxDb::SetSqlLogging(wxDbSqlLogState state, const wxString &filename, bool append)
{
wxASSERT(state == sqlLogON || state == sqlLogOFF);
bool wxDb::SetSqlLogging(wxDbSqlLogState state, const wxString &filename, bool append)
{
wxASSERT(state == sqlLogON || state == sqlLogOFF);
int dataType, ULONG columnLength,
const wxString &optionalParam)
{
int dataType, ULONG columnLength,
const wxString &optionalParam)
{
wxASSERT((dataType == DB_DATA_TYPE_VARCHAR && columnLength > 0) ||
dataType != DB_DATA_TYPE_VARCHAR);
wxASSERT((dataType == DB_DATA_TYPE_VARCHAR && columnLength > 0) ||
dataType != DB_DATA_TYPE_VARCHAR);
// embedded nulls in strings
setupStr.Printf(wxT("DSN=%s%cDescription=%s%cDefaultDir=%s%c"),dsn,2,description,2,defDir,2);
// embedded nulls in strings
setupStr.Printf(wxT("DSN=%s%cDescription=%s%cDefaultDir=%s%c"),dsn,2,description,2,defDir,2);
********************************************************************
*
* The following functions are all DEPRECATED and are included for
********************************************************************
*
* The following functions are all DEPRECATED and are included for
*
********************************************************************
********************************************************************/
*
********************************************************************
********************************************************************/