X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/bf5423ea7dd9f6a5c1d5eae71af034ff1aead158..e5c4c38b5d3523bfac08987b5ec09d34f4f61caa:/src/common/db.cpp diff --git a/src/common/db.cpp b/src/common/db.cpp index 523da04b94..08c40f003d 100644 --- a/src/common/db.cpp +++ b/src/common/db.cpp @@ -34,53 +34,32 @@ // SYNOPSIS START // SYNOPSIS STOP */ +#ifdef __GNUG__ + #pragma implementation "db.h" +#endif #include "wx/wxprec.h" - -// Use this line for wxWindows v1.x -//#include "wx_ver.h" -// Use this line for wxWindows v2.x -#include "wx/version.h" - -#if wxMAJOR_VERSION == 2 - #ifdef __GNUG__ - #pragma implementation "db.h" - #endif +#ifdef __BORLANDC__ + #pragma hdrstop #endif #ifdef DBDEBUG_CONSOLE #include "wx/ioswrap.h" #endif -#ifdef __BORLANDC__ - #pragma hdrstop -#endif //__BORLANDC__ - -#if wxMAJOR_VERSION == 2 - #ifndef WX_PRECOMP - #include "wx/string.h" - #include "wx/object.h" - #include "wx/list.h" - #include "wx/utils.h" +#ifndef WX_PRECOMP + #include "wx/string.h" + #include "wx/object.h" + #include "wx/list.h" + #include "wx/utils.h" + #if wxUSE_GUI #include "wx/msgdlg.h" - #include "wx/log.h" #endif - #include "wx/filefn.h" - #include "wx/wxchar.h" -#endif - - -#if wxMAJOR_VERSION == 1 -# if defined(wx_msw) || defined(wx_x) -# ifdef WX_PRECOMP -# include "wx_prec.h" -# else -# include "wx.h" -# endif -# endif -# define wxUSE_ODBC 1 + #include "wx/log.h" #endif +#include "wx/filefn.h" +#include "wx/wxchar.h" #if wxUSE_ODBC @@ -90,11 +69,7 @@ #include #include -#if wxMAJOR_VERSION == 1 - #include "db.h" -#elif wxMAJOR_VERSION == 2 - #include "wx/db.h" -#endif +#include "wx/db.h" WXDLLEXPORT_DATA(wxDbList*) PtrBegDbList = 0; @@ -121,6 +96,7 @@ static wxString SQLLOGfn = SQL_LOG_FILENAME; // 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 @@ -146,7 +122,7 @@ wxDbConnectInf::wxDbConnectInf() /********** wxDbConnectInf Constructor - form 2 **********/ -wxDbConnectInf::wxDbConnectInf(HENV henv, const wxString &dsn, const wxString &userID, +wxDbConnectInf::wxDbConnectInf(HENV henv, const wxString &dsn, const wxString &userID, const wxString &password, const wxString &defaultDir, const wxString &fileType, const wxString &description) { @@ -250,7 +226,7 @@ void wxDbConnectInf::SetUserID(const wxString &uid) void wxDbConnectInf::SetPassword(const wxString &password) { wxASSERT(password.Length() < sizeof(AuthStr)); - + wxStrcpy(AuthStr,password); } // wxDbConnectInf::SetPassword() @@ -366,9 +342,9 @@ int wxDbColFor::Format(int Nation, int dbDataType, SWORD sqlDataType, s_Field = wxT("%02d/%02d/%04d %02d:%02d:%02d.%03d"); } break; - case DB_DATA_TYPE_BLOB: + case DB_DATA_TYPE_BLOB: s_Field.Printf(wxT("Unable to format(%d)-SQL(%d)"),dbDataType,sqlDataType); // - break; + break; default: s_Field.Printf(wxT("Unknown Format(%d)-SQL(%d)"),dbDataType,sqlDataType); // break; @@ -475,7 +451,7 @@ bool wxDbInf::Initialize() } // wxDbInf::Initialize() -/********** wxDb Constructors **********/ +/********** wxDb Constructor **********/ wxDb::wxDb(const HENV &aHenv, bool FwdOnlyCursors) { // Copy the HENV into the db class @@ -486,6 +462,19 @@ wxDb::wxDb(const HENV &aHenv, bool FwdOnlyCursors) } // 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() @@ -550,6 +539,7 @@ void wxDb::initialize() // Mark database as not open as of yet dbIsOpen = FALSE; + dbIsCached = FALSE; } // wxDb::initialize() @@ -572,7 +562,8 @@ const wxChar *wxDb::convertUserID(const wxChar *userID, wxString &UserID) UserID.Empty(); // dBase does not use user names, and some drivers fail if you try to pass one - if (Dbms() == dbmsDBASE) + if ( Dbms() == dbmsDBASE + || Dbms() == dbmsXBASE_SEQUITER ) UserID.Empty(); // Oracle user names may only be in uppercase, so force @@ -585,7 +576,7 @@ const wxChar *wxDb::convertUserID(const wxChar *userID, wxString &UserID) /********** wxDb::Open() **********/ -bool wxDb::Open(const wxString &Dsn, const wxString &Uid, const wxString &AuthStr) +bool wxDb::Open(const wxString &Dsn, const wxString &Uid, const wxString &AuthStr, bool failOnDataTypeUnsupported) { wxASSERT(Dsn.Length()); dsn = Dsn; @@ -613,18 +604,9 @@ bool wxDb::Open(const wxString &Dsn, const wxString &Uid, const wxString &AuthSt (UCHAR FAR *) uid.c_str(), SQL_NTS, (UCHAR FAR *) authStr.c_str(), SQL_NTS); -/* - if (retcode == SQL_SUCCESS_WITH_INFO) - DispAllErrors(henv, hdbc); - else if (retcode != SQL_SUCCESS) - return(DispAllErrors(henv, hdbc)); - - if (retcode == SQL_ERROR) - return(DispAllErrors(henv, hdbc)); -*/ - if ((retcode != SQL_SUCCESS) && + if ((retcode != SQL_SUCCESS) && (retcode != SQL_SUCCESS_WITH_INFO)) - return(DispAllErrors(henv, hdbc)); + return(DispAllErrors(henv, hdbc)); /* If using Intersolv branded ODBC drivers, this is the place where you would substitute @@ -705,7 +687,10 @@ bool wxDb::Open(const wxString &Dsn, const wxString &Uid, const wxString &AuthSt if (!getDataTypeInfo(SQL_FLOAT,typeInfFloat)) if (!getDataTypeInfo(SQL_DECIMAL,typeInfFloat)) if (!getDataTypeInfo(SQL_NUMERIC,typeInfFloat)) - return(FALSE); + { + if (failOnDataTypeUnsupported) + return(FALSE); + } else typeInfFloat.FsqlType = SQL_NUMERIC; else @@ -723,7 +708,10 @@ bool wxDb::Open(const wxString &Dsn, const wxString &Uid, const wxString &AuthSt // 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); + { + if (failOnDataTypeUnsupported) + return(FALSE); + } else typeInfInteger.FsqlType = typeInfFloat.FsqlType; } @@ -731,30 +719,41 @@ bool wxDb::Open(const wxString &Dsn, const wxString &Uid, const wxString &AuthSt typeInfInteger.FsqlType = SQL_INTEGER; // Date/Time - if (Dbms() != dbmsDBASE) - { - if (! getDataTypeInfo(SQL_TIMESTAMP,typeInfDate)) - return(FALSE); - else - typeInfDate.FsqlType = SQL_TIMESTAMP; - } - else + if (!getDataTypeInfo(SQL_TIMESTAMP,typeInfDate)) { if (!getDataTypeInfo(SQL_DATE,typeInfDate)) - return(FALSE); + { +#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)) - return(FALSE); + { + if (failOnDataTypeUnsupported) + return(FALSE); + } else - typeInfInteger.FsqlType = SQL_VARBINARY; + typeInfBlob.FsqlType = SQL_VARBINARY; } else - typeInfInteger.FsqlType = SQL_LONGVARBINARY; + typeInfBlob.FsqlType = SQL_LONGVARBINARY; //typeInfBlob.TypeName = "BLOB"; @@ -807,8 +806,8 @@ bool wxDb::Open(wxDb *copyDb) (UCHAR FAR *) uid.c_str(), SQL_NTS, (UCHAR FAR *) authStr.c_str(), SQL_NTS); - if (retcode == SQL_ERROR) - return(DispAllErrors(henv, hdbc)); + if (retcode == SQL_ERROR) + return(DispAllErrors(henv, hdbc)); /* If using Intersolv branded ODBC drivers, this is the place where you would substitute @@ -927,7 +926,7 @@ bool wxDb::setConnectionOptions(void) SQLSetConnectOption(hdbc, SQL_AUTOCOMMIT, SQL_AUTOCOMMIT_OFF); SQLSetConnectOption(hdbc, SQL_OPT_TRACE, SQL_OPT_TRACE_OFF); -// SQLSetConnectOption(hdbc, SQL_TXN_ISOLATION, SQL_TXN_READ_COMMITTED); // No dirty reads +// SQLSetConnectOption(hdbc, SQL_TXN_ISOLATION, SQL_TXN_READ_COMMITTED); // No dirty reads // By default, MS Sql Server closes cursors on commit and rollback. The following // call to SQLSetConnectOption() is needed to force SQL Server to preserve cursors @@ -1305,8 +1304,10 @@ bool wxDb::getDataTypeInfo(SWORD fSqlType, wxDbSqlTypeInfo &structSQLTypeInfo) // Get information about the data type specified if (SQLGetTypeInfo(hstmt, fSqlType) != SQL_SUCCESS) return(DispAllErrors(henv, hdbc, hstmt)); + // Fetch the record - if ((retcode = SQLFetch(hstmt)) != SQL_SUCCESS) + retcode = SQLFetch(hstmt); + if (retcode != SQL_SUCCESS) { #ifdef DBDEBUG_CONSOLE if (retcode == SQL_NO_DATA_FOUND) @@ -1318,6 +1319,7 @@ bool wxDb::getDataTypeInfo(SWORD fSqlType, wxDbSqlTypeInfo &structSQLTypeInfo) } wxChar typeName[DB_TYPE_NAME_LEN+1]; + // Obtain columns from the record if (SQLGetData(hstmt, 1, SQL_C_CHAR, (UCHAR*) typeName, DB_TYPE_NAME_LEN, &cbRet) != SQL_SUCCESS) return(DispAllErrors(henv, hdbc, hstmt)); @@ -1415,7 +1417,7 @@ void wxDb::Close(void) { s.Printf(wxT("(%-20s) tableID:[%6lu] pDb:[%p]"), tiu->tableName,tiu->tableID,tiu->pDb); s2.Printf(wxT("Orphaned found using pDb:[%p]"),this); - wxLogDebug (s,s2); + wxLogDebug (s.c_str(),s2.c_str()); } pNode = pNode->Next(); } @@ -1426,7 +1428,7 @@ void wxDb::Close(void) for (i = 0; i < DB_MAX_ERROR_HISTORY; i++) wxStrcpy(DBerrorList[i], errorList[i]); - dbmsType = dbmsUNIDENTIFIED; + dbmsType = dbmsUNIDENTIFIED; dbIsOpen = FALSE; } // wxDb::Close() @@ -1499,7 +1501,7 @@ bool wxDb::DispAllErrors(HENV aHenv, HDBC aHdbc, HSTMT aHstmt) } } - return(FALSE); // This function always returns false. + return(FALSE); // This function always returns FALSE. } // wxDb::DispAllErrors() @@ -1794,7 +1796,7 @@ bool wxDb::Grant(int privileges, const wxString &tableName, const wxString &user } sqlStmt += wxT(" ON "); - sqlStmt += tableName; + sqlStmt += SQLTableName(tableName); sqlStmt += wxT(" TO "); sqlStmt += userList; @@ -1881,7 +1883,7 @@ bool wxDb::DropView(const wxString &viewName) } // Commit the transaction - if (! CommitTrans()) + if (!CommitTrans()) return(FALSE); return TRUE; @@ -1892,9 +1894,16 @@ bool wxDb::DropView(const wxString &viewName) /********** wxDb::ExecSql() **********/ bool wxDb::ExecSql(const wxString &pSqlStmt) { + RETCODE retcode; + SQLFreeStmt(hstmt, SQL_CLOSE); - if (SQLExecDirect(hstmt, (UCHAR FAR *) pSqlStmt.c_str(), SQL_NTS) == SQL_SUCCESS) + + retcode = SQLExecDirect(hstmt, (UCHAR FAR *) pSqlStmt.c_str(), SQL_NTS); + if (retcode == SQL_SUCCESS || + (Dbms() == dbmsDB2 && (retcode == SQL_SUCCESS_WITH_INFO || retcode == SQL_NO_DATA_FOUND))) + { return(TRUE); + } else { DispAllErrors(henv, hdbc, hstmt); @@ -1936,7 +1945,7 @@ bool wxDb::GetData(UWORD colNo, SWORD cType, PTR pData, SDWORD maxLen, SDWORD FA /********** wxDb::GetKeyFields() **********/ -int wxDb::GetKeyFields(const wxString &tableName, wxDbColInf* colInf, int noCols) +int wxDb::GetKeyFields(const wxString &tableName, wxDbColInf* colInf, UWORD noCols) { wxChar szPkTable[DB_MAX_TABLE_NAME_LEN+1]; /* Primary key table name */ wxChar szFkTable[DB_MAX_TABLE_NAME_LEN+1]; /* Foreign key table name */ @@ -1946,7 +1955,7 @@ int wxDb::GetKeyFields(const wxString &tableName, wxDbColInf* colInf, int noCols wxChar szFkCol[DB_MAX_COLUMN_NAME_LEN+1]; /* Foreign key column */ SQLRETURN retcode; SDWORD cb; - int i; + SWORD i; wxString tempStr; /* * ----------------------------------------------------------------------- @@ -2104,8 +2113,8 @@ wxDbColInf *wxDb::GetColumns(wxChar *tableName[], const wxChar *userID) * to avoid undesired unbinding of columns. */ { - int noCols = 0; - int colNo = 0; + UWORD noCols = 0; + UWORD colNo = 0; wxDbColInf *colInf = 0; RETCODE retcode; @@ -2246,7 +2255,7 @@ wxDbColInf *wxDb::GetColumns(wxChar *tableName[], const wxChar *userID) /********** wxDb::GetColumns() **********/ -wxDbColInf *wxDb::GetColumns(const wxString &tableName, int *numCols, const wxChar *userID) +wxDbColInf *wxDb::GetColumns(const wxString &tableName, UWORD *numCols, const wxChar *userID) // // Same as the above GetColumns() function except this one gets columns // only for a single table, and if 'numCols' is not NULL, the number of @@ -2262,8 +2271,8 @@ wxDbColInf *wxDb::GetColumns(const wxString &tableName, int *numCols, const wxCh // to avoid undesired unbinding of columns. { - int noCols = 0; - int colNo = 0; + UWORD noCols = 0; + UWORD colNo = 0; wxDbColInf *colInf = 0; RETCODE retcode; @@ -2447,7 +2456,7 @@ wxDbColInf *wxDb::GetColumns(const wxString &tableName, int *numCols, const wxCh typedef struct { - int noCols; + UWORD noCols; wxDbColInf *colInf; } _TableColumns; @@ -2458,7 +2467,7 @@ wxDbColInf *wxDb::GetColumns(wxChar *tableName[], const wxChar *userID) // The last array element of the tableName[] argument must be zero (null). // This is how the end of the array is detected. - int noCols = 0; + UWORD noCols = 0; // How many tables ? int tbl; @@ -2517,8 +2526,8 @@ wxDbColInf *wxDb::GetColumns(const wxString &tableName, int *numCols, const wxCh // by this function. This function should use its own wxDb instance // to avoid undesired unbinding of columns. { - SWORD noCols = 0; - int colNo = 0; + UWORD noCols = 0; + UWORD colNo = 0; wxDbColInf *colInf = 0; RETCODE retcode; @@ -2690,7 +2699,7 @@ wxDbColInf *wxDb::GetColumns(const wxString &tableName, int *numCols, const wxCh // Build a generic SELECT statement which returns 0 rows wxString Stmt; - Stmt.Printf(wxT("select * from %s where 0=1"), tableName); + Stmt.Printf(wxT("select * from \"%s\" where 0=1"), tableName); // Execute query if (SQLExecDirect(hstmt, (UCHAR FAR *) Stmt.c_str(), SQL_NTS) != SQL_SUCCESS) @@ -2778,7 +2787,7 @@ int wxDb::GetColumnCount(const wxString &tableName, const wxChar *userID) * to avoid undesired unbinding of columns. */ { - int noCols = 0; + UWORD noCols = 0; RETCODE retcode; @@ -2983,7 +2992,7 @@ bool wxDb::Catalog(const wxChar *userID, const wxString &fileName) wxChar colName[DB_MAX_COLUMN_NAME_LEN+1]; SWORD sqlDataType; wxChar typeName[30+1]; - SWORD precision, length; + SDWORD precision, length; FILE *fp = fopen(fileName.c_str(),wxT("wt")); if (fp == NULL) @@ -2997,6 +3006,7 @@ bool wxDb::Catalog(const wxChar *userID, const wxString &fileName) if (!UserID.IsEmpty() && Dbms() != dbmsMY_SQL && Dbms() != dbmsACCESS && + Dbms() != dbmsINTERBASE && Dbms() != dbmsMS_SQL_SERVER) { retcode = SQLColumns(hstmt, @@ -3024,8 +3034,12 @@ bool wxDb::Catalog(const wxChar *userID, const wxString &fileName) tblNameSave.Empty(); int cnt = 0; - while ((retcode = SQLFetch(hstmt)) == SQL_SUCCESS) + while (TRUE) { + retcode = SQLFetch(hstmt); + if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO) + break; + if (wxStrcmp(tblName, tblNameSave.c_str())) { if (cnt) @@ -3046,12 +3060,12 @@ bool wxDb::Catalog(const wxChar *userID, const wxString &fileName) tblNameSave = tblName; } - GetData(3,SQL_C_CHAR, (UCHAR *)tblName, DB_MAX_TABLE_NAME_LEN+1, &cb); - GetData(4,SQL_C_CHAR, (UCHAR *)colName, DB_MAX_COLUMN_NAME_LEN+1,&cb); - GetData(5,SQL_C_SSHORT,(UCHAR *)&sqlDataType,0, &cb); - GetData(6,SQL_C_CHAR, (UCHAR *)typeName, sizeof(typeName), &cb); - GetData(7,SQL_C_SSHORT,(UCHAR *)&precision, 0, &cb); - GetData(8,SQL_C_SSHORT,(UCHAR *)&length, 0, &cb); + GetData(3,SQL_C_CHAR, (UCHAR *) tblName, DB_MAX_TABLE_NAME_LEN+1, &cb); + GetData(4,SQL_C_CHAR, (UCHAR *) colName, DB_MAX_COLUMN_NAME_LEN+1,&cb); + GetData(5,SQL_C_SSHORT,(UCHAR *)&sqlDataType, 0, &cb); + GetData(6,SQL_C_CHAR, (UCHAR *) typeName, sizeof(typeName), &cb); + GetData(7,SQL_C_SLONG, (UCHAR *)&precision, 0, &cb); + GetData(8,SQL_C_SLONG, (UCHAR *)&length, 0, &cb); outStr.Printf(wxT("%-32s %-32s (%04d)%-15s %9d %9d\n"), tblName, colName, sqlDataType, typeName, precision, length); @@ -3077,7 +3091,7 @@ bool wxDb::Catalog(const wxChar *userID, const wxString &fileName) bool wxDb::TableExists(const wxString &tableName, const wxChar *userID, const wxString &tablePath) /* - * Table name can refer to a table, view, alias or synonym. Returns true + * Table name can refer to a table, view, alias or synonym. Returns TRUE * if the object exists in the database. This function does not indicate * whether or not the user has privleges to query or perform other functions * on the table. @@ -3123,7 +3137,10 @@ bool wxDb::TableExists(const wxString &tableName, const wxChar *userID, const wx if (!UserID.IsEmpty() && Dbms() != dbmsMY_SQL && Dbms() != dbmsACCESS && - Dbms() != dbmsMS_SQL_SERVER) + Dbms() != dbmsMS_SQL_SERVER && + Dbms() != dbmsDB2 && + Dbms() != dbmsINTERBASE && + Dbms() != dbmsPERVASIVE_SQL) { retcode = SQLTables(hstmt, NULL, 0, // All qualifiers @@ -3172,8 +3189,9 @@ bool wxDb::TablePrivileges(const wxString &tableName, const wxString &priv, cons wxString TableName; - wxString UserID; + wxString UserID,Schema; convertUserID(userID,UserID); + convertUserID(schema,Schema); TableName = tableName; // Oracle and Interbase table names are uppercase only, so force @@ -3184,18 +3202,23 @@ bool wxDb::TablePrivileges(const wxString &tableName, const wxString &priv, cons SQLFreeStmt(hstmt, SQL_CLOSE); - if (!schema) + // Some databases cannot accept a user name when looking up table names, + // so we use the call below that leaves out the user name + if (!Schema.IsEmpty() && + Dbms() != dbmsMY_SQL && + Dbms() != dbmsACCESS && + Dbms() != dbmsMS_SQL_SERVER) { retcode = SQLTablePrivileges(hstmt, NULL, 0, // Catalog - NULL, 0, // Schema + (UCHAR FAR *)Schema.c_str(), SQL_NTS, // Schema (UCHAR FAR *)TableName.c_str(), SQL_NTS); } else { retcode = SQLTablePrivileges(hstmt, NULL, 0, // Catalog - (UCHAR FAR *)schema, SQL_NTS, // Schema + NULL, 0, // Schema (UCHAR FAR *)TableName.c_str(), SQL_NTS); } @@ -3206,30 +3229,35 @@ bool wxDb::TablePrivileges(const wxString &tableName, const wxString &priv, cons if ((retcode != SQL_SUCCESS) && (retcode != SQL_SUCCESS_WITH_INFO)) return(DispAllErrors(henv, hdbc, hstmt)); + bool failed = FALSE; retcode = SQLFetch(hstmt); while (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) { if (SQLGetData(hstmt, 1, SQL_C_CHAR, (UCHAR*) result.tableQual, sizeof(result.tableQual), &cbRetVal) != SQL_SUCCESS) - return(DispAllErrors(henv, hdbc, hstmt)); + failed = TRUE; - if (SQLGetData(hstmt, 2, SQL_C_CHAR, (UCHAR*) result.tableOwner, sizeof(result.tableOwner), &cbRetVal) != SQL_SUCCESS) - return(DispAllErrors(henv, hdbc, hstmt)); + if (!failed && SQLGetData(hstmt, 2, SQL_C_CHAR, (UCHAR*) result.tableOwner, sizeof(result.tableOwner), &cbRetVal) != SQL_SUCCESS) + failed = TRUE; - if (SQLGetData(hstmt, 3, SQL_C_CHAR, (UCHAR*) result.tableName, sizeof(result.tableName), &cbRetVal) != SQL_SUCCESS) - return(DispAllErrors(henv, hdbc, hstmt)); + if (!failed && SQLGetData(hstmt, 3, SQL_C_CHAR, (UCHAR*) result.tableName, sizeof(result.tableName), &cbRetVal) != SQL_SUCCESS) + failed = TRUE; - if (SQLGetData(hstmt, 4, SQL_C_CHAR, (UCHAR*) result.grantor, sizeof(result.grantor), &cbRetVal) != SQL_SUCCESS) - return(DispAllErrors(henv, hdbc, hstmt)); + if (!failed && SQLGetData(hstmt, 4, SQL_C_CHAR, (UCHAR*) result.grantor, sizeof(result.grantor), &cbRetVal) != SQL_SUCCESS) + failed = TRUE; - if (SQLGetData(hstmt, 5, SQL_C_CHAR, (UCHAR*) result.grantee, sizeof(result.grantee), &cbRetVal) != SQL_SUCCESS) - return(DispAllErrors(henv, hdbc, hstmt)); + if (!failed && SQLGetData(hstmt, 5, SQL_C_CHAR, (UCHAR*) result.grantee, sizeof(result.grantee), &cbRetVal) != SQL_SUCCESS) + failed = TRUE; - if (SQLGetData(hstmt, 6, SQL_C_CHAR, (UCHAR*) result.privilege, sizeof(result.privilege), &cbRetVal) != SQL_SUCCESS) - return(DispAllErrors(henv, hdbc, hstmt)); + if (!failed && SQLGetData(hstmt, 6, SQL_C_CHAR, (UCHAR*) result.privilege, sizeof(result.privilege), &cbRetVal) != SQL_SUCCESS) + failed = TRUE; - if (SQLGetData(hstmt, 7, SQL_C_CHAR, (UCHAR*) result.grantable, sizeof(result.grantable), &cbRetVal) != SQL_SUCCESS) - return(DispAllErrors(henv, hdbc, hstmt)); + if (!failed && SQLGetData(hstmt, 7, SQL_C_CHAR, (UCHAR*) result.grantable, sizeof(result.grantable), &cbRetVal) != SQL_SUCCESS) + failed = TRUE; + if (failed) + { + return(DispAllErrors(henv, hdbc, hstmt)); + } #ifdef DBDEBUG_CONSOLE fprintf(stderr,wxT("Scanning %s privilege on table %s.%s granted by %s to %s\n"), result.privilege,result.tableOwner,result.tableName, @@ -3265,6 +3293,34 @@ bool wxDb::TablePrivileges(const wxString &tableName, const wxString &priv, cons } // wxDb::TablePrivileges +const wxString wxDb::SQLTableName(const wxChar *tableName) +{ + wxString TableName; + + if (Dbms() == dbmsACCESS) + TableName = '"'; + TableName += tableName; + if (Dbms() == dbmsACCESS) + TableName += '"'; + + return TableName; +} // wxDb::SQLTableName() + + +const wxString wxDb::SQLColumnName(const wxChar *colName) +{ + wxString ColName; + + if (Dbms() == dbmsACCESS) + ColName = '"'; + ColName += colName; + if (Dbms() == dbmsACCESS) + ColName += '"'; + + return ColName; +} // wxDb::SQLColumnName() + + /********** wxDb::SetSqlLogging() **********/ bool wxDb::SetSqlLogging(wxDbSqlLogState state, const wxString &filename, bool append) { @@ -3367,7 +3423,16 @@ wxDBMS wxDb::Dbms(void) * * DB2 * - Primary keys must be declared as NOT NULL + * - Table and index names must not be longer than 13 characters in length (technically + * table names can be up to 18 characters, but the primary index is created using the + * base table name plus "_PIDX", so the limit if the table has a primary index is 13. + * + * PERVASIVE SQL * + * INTERBASE + * - Columns that are part of primary keys must be defined as being NOT NULL + * when they are created. Some code is added in ::CreateIndex to try to adjust the + * column definition if it is not defined correctly, but it is experimental */ { // Should only need to do this once for each new database connection @@ -3400,9 +3465,9 @@ wxDBMS wxDb::Dbms(void) { if (!wxStrncmp(dbInf.driverName, wxT("oplodbc"), 7) || !wxStrncmp(dbInf.driverName, wxT("OLOD"), 4)) - return ((wxDBMS)(dbmsMS_SQL_SERVER)); - else - return ((wxDBMS)(dbmsType = dbmsSYBASE_ASE)); + return ((wxDBMS)(dbmsMS_SQL_SERVER)); + else + return ((wxDBMS)(dbmsType = dbmsSYBASE_ASE)); } if (!wxStricmp(dbInf.dbmsName,wxT("Microsoft SQL Server"))) @@ -3412,6 +3477,10 @@ wxDBMS wxDb::Dbms(void) if (!wxStricmp(dbInf.dbmsName,wxT("PostgreSQL"))) // v6.5.0 return((wxDBMS)(dbmsType = dbmsPOSTGRES)); + baseName[9] = 0; + if (!wxStricmp(dbInf.dbmsName,wxT("Pervasive"))) + return((wxDBMS)(dbmsType = dbmsPERVASIVE_SQL)); + baseName[8] = 0; if (!wxStricmp(baseName,wxT("Informix"))) return((wxDBMS)(dbmsType = dbmsINFORMIX)); @@ -3430,6 +3499,12 @@ wxDBMS wxDb::Dbms(void) if (!wxStricmp(baseName,wxT("DBASE"))) return((wxDBMS)(dbmsType = dbmsDBASE)); + if (!wxStricmp(baseName,wxT("xBase"))) + return((wxDBMS)(dbmsType = dbmsXBASE_SEQUITER)); + + if (!wxStricmp(baseName,wxT("MySQL"))) + return((wxDBMS)(dbmsType = dbmsMY_SQL)); + baseName[3] = 0; if (!wxStricmp(baseName,wxT("DB2"))) return((wxDBMS)(dbmsType = dbmsDBASE)); @@ -3451,60 +3526,70 @@ bool wxDb::ModifyColumn(const wxString &tableName, const wxString &columnName, // Must specify a columnLength if modifying a VARCHAR type column if (dataType == DB_DATA_TYPE_VARCHAR && !columnLength) return FALSE; - + wxString dataTypeName; - wxString sqlStmt; + wxString sqlStmt; wxString alterSlashModify; - switch(dataType) - { - case DB_DATA_TYPE_VARCHAR : - dataTypeName = typeInfVarchar.TypeName; - break; - case DB_DATA_TYPE_INTEGER : - dataTypeName = typeInfInteger.TypeName; - break; - case DB_DATA_TYPE_FLOAT : - dataTypeName = typeInfFloat.TypeName; - break; - case DB_DATA_TYPE_DATE : - dataTypeName = typeInfDate.TypeName; - break; - case DB_DATA_TYPE_BLOB : - dataTypeName = typeInfBlob.TypeName; - break; - default: - return FALSE; - } - - // Set the modify or alter syntax depending on the type of database connected to - switch (Dbms()) - { - case dbmsORACLE : - alterSlashModify = "MODIFY"; - break; - case dbmsMS_SQL_SERVER : - alterSlashModify = "ALTER COLUMN"; - break; - case dbmsUNIDENTIFIED : + switch(dataType) + { + case DB_DATA_TYPE_VARCHAR : + dataTypeName = typeInfVarchar.TypeName; + break; + case DB_DATA_TYPE_INTEGER : + dataTypeName = typeInfInteger.TypeName; + break; + case DB_DATA_TYPE_FLOAT : + dataTypeName = typeInfFloat.TypeName; + break; + case DB_DATA_TYPE_DATE : + dataTypeName = typeInfDate.TypeName; + break; + case DB_DATA_TYPE_BLOB : + dataTypeName = typeInfBlob.TypeName; + break; + default: + return FALSE; + } + + // Set the modify or alter syntax depending on the type of database connected to + switch (Dbms()) + { + case dbmsORACLE : + alterSlashModify = "MODIFY"; + break; + case dbmsMS_SQL_SERVER : + alterSlashModify = "ALTER COLUMN"; + break; + case dbmsUNIDENTIFIED : return FALSE; - case dbmsSYBASE_ASA : - case dbmsSYBASE_ASE : - case dbmsMY_SQL : - case dbmsPOSTGRES : - case dbmsACCESS : - case dbmsDBASE : - default : - alterSlashModify = "MODIFY"; - break; - } - - // create the SQL statement - sqlStmt.Printf(wxT("ALTER TABLE %s %s %s %s"), tableName.c_str(), alterSlashModify.c_str(), - columnName.c_str(), dataTypeName.c_str()); + case dbmsSYBASE_ASA : + case dbmsSYBASE_ASE : + case dbmsMY_SQL : + case dbmsPOSTGRES : + case dbmsACCESS : + case dbmsDBASE : + case dbmsXBASE_SEQUITER : + default : + alterSlashModify = "MODIFY"; + break; + } + + // create the SQL statement + if ( Dbms() == dbmsMY_SQL ) + { + sqlStmt.Printf(wxT("ALTER TABLE %s %s %s %s"), tableName.c_str(), alterSlashModify.c_str(), + columnName.c_str(), dataTypeName.c_str()); + } + else + { + sqlStmt.Printf(wxT("ALTER TABLE \"%s\" \"%s\" \"%s\" %s"), tableName.c_str(), alterSlashModify.c_str(), + columnName.c_str(), dataTypeName.c_str()); + } // For varchars only, append the size of the column - if (dataType == DB_DATA_TYPE_VARCHAR) + if (dataType == DB_DATA_TYPE_VARCHAR && + (Dbms() != dbmsMY_SQL || dataTypeName != "text")) { wxString s; s.Printf(wxT("(%d)"), columnLength); @@ -3518,7 +3603,7 @@ bool wxDb::ModifyColumn(const wxString &tableName, const wxString &columnName, sqlStmt += optionalParam; } - return ExecSql(sqlStmt); + return ExecSql(sqlStmt); } // wxDb::ModifyColumn() @@ -3576,7 +3661,7 @@ wxDb WXDLLEXPORT *wxDbGetConnection(wxDbConnectInf *pDbConfig, bool FwdOnlyCurso // Initialize new node in the linked list pList->PtrNext = 0; pList->Free = FALSE; - pList->Dsn = pDbConfig->GetDsn(); //glt - will this assignment work? + pList->Dsn = pDbConfig->GetDsn(); pList->Uid = pDbConfig->GetUserID(); pList->AuthStr = pDbConfig->GetPassword(); @@ -3592,6 +3677,7 @@ wxDb WXDLLEXPORT *wxDbGetConnection(wxDbConnectInf *pDbConfig, bool FwdOnlyCurso // Connect to the datasource if (opened) { + pList->PtrDb->setCached(TRUE); // Prevent a user from deleting a cached connection pList->PtrDb->SetSqlLogging(SQLLOGstate,SQLLOGfn,TRUE); return(pList->PtrDb); } @@ -3640,6 +3726,7 @@ void WXDLLEXPORT wxDbCloseConnections(void) pNext = pList->PtrNext; // Save the pointer to next pList->PtrDb->CommitTrans(); // Commit any open transactions on wxDb object pList->PtrDb->Close(); // Close the wxDb object + pList->PtrDb->setCached(FALSE); // Allows deletion of the wxDb instance delete pList->PtrDb; // Deletes the wxDb object delete pList; // Deletes the linked list object } @@ -3668,6 +3755,54 @@ int WXDLLEXPORT wxDbConnectionsInUse(void) } // wxDbConnectionsInUse() + +/********** wxDbLogExtendedErrorMsg() **********/ +// DEBUG ONLY function +const wxChar* WXDLLEXPORT wxDbLogExtendedErrorMsg(const wxChar *userText, + wxDb *pDb, + const wxChar *ErrFile, + int ErrLine) +{ + static wxString msg; + msg = userText; + + wxString tStr; + + if (ErrFile || ErrLine) + { + msg += wxT("File: "); + msg += ErrFile; + msg += wxT(" Line: "); + tStr.Printf(wxT("%d"),ErrLine); + msg += tStr.c_str(); + msg += wxT("\n"); + } + + msg.Append (wxT("\nODBC errors:\n")); + msg += wxT("\n"); + + // Display errors for this connection + int i; + for (i = 0; i < DB_MAX_ERROR_HISTORY; i++) + { + if (pDb->errorList[i]) + { + msg.Append(pDb->errorList[i]); + if (wxStrcmp(pDb->errorList[i],wxT("")) != 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("")); + } + } + msg += wxT("\n"); + + wxLogDebug(msg.c_str()); + + return msg.c_str(); +} // wxDbLogExtendedErrorMsg() + + /********** wxDbSqlLog() **********/ bool wxDbSqlLog(wxDbSqlLogState state, const wxChar *filename) {