X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/5a226de06289ba03a767f6643ff62042ba348e68..dc9b623b9561db9a164969e7eec3c1853e839cfb:/src/common/dbtable.cpp?ds=sidebyside diff --git a/src/common/dbtable.cpp b/src/common/dbtable.cpp index 0df9c08bc4..661af5ebb6 100644 --- a/src/common/dbtable.cpp +++ b/src/common/dbtable.cpp @@ -24,51 +24,32 @@ // SYNOPSIS START // SYNOPSIS STOP */ +#ifdef __GNUG__ + #pragma implementation "dbtable.h" +#endif -// Use this line for wxWindows v1.x -//#include "wx_ver.h" -// Use this line for wxWindows v2.x #include "wx/wxprec.h" -#include "wx/version.h" -#if wxMAJOR_VERSION == 2 - #ifdef __GNUG__ - #pragma implementation "dbtable.h" - #endif +#ifdef __BORLANDC__ + #pragma hdrstop #endif #ifdef DBDEBUG_CONSOLE + #include "iostream.h" #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/log.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 -#endif - +#include "wx/filefn.h" #if wxUSE_ODBC @@ -77,11 +58,7 @@ #include //#include -#if wxMAJOR_VERSION == 1 - #include "table.h" -#elif wxMAJOR_VERSION == 2 - #include "wx/dbtable.h" -#endif +#include "wx/dbtable.h" #ifdef __UNIX__ // The HPUX preprocessor lines below were commented out on 8/20/97 @@ -162,6 +139,7 @@ bool wxDbTable::initialize(wxDb *pwxDb, const wxString &tblName, const UWORD num henv = 0; hdbc = 0; hstmt = 0; + m_hstmtGridQuery = 0; hstmtDefault = 0; // Initialized below hstmtCount = 0; // Initialized first time it is needed hstmtInsert = 0; @@ -192,18 +170,18 @@ bool wxDbTable::initialize(wxDb *pwxDb, const wxString &tblName, const UWORD num tablePath = tblPath; // Table Path - used for dBase files else tablePath.Empty(); - + if (qryTblName.Length()) // Name of the table/view to query queryTableName = qryTblName; else queryTableName = tblName; - + pDb->incrementTableCount(); - + wxString s; tableID = ++lastTableID; s.Printf(wxT("wxDbTable constructor (%-20s) tableID:[%6lu] pDb:[%p]"), tblName.c_str(), tableID, pDb); - + #ifdef __WXDEBUG__ wxTablesInUse *tableInUse; tableInUse = new wxTablesInUse(); @@ -212,17 +190,17 @@ bool wxDbTable::initialize(wxDb *pwxDb, const wxString &tblName, const UWORD num tableInUse->pDb = pDb; TablesInUse.Append(tableInUse); #endif - + pDb->WriteSqlLog(s); - + // Grab the HENV and HDBC from the wxDb object henv = pDb->GetHENV(); hdbc = pDb->GetHDBC(); - + // Allocate space for column definitions if (noCols) colDefs = new wxDbColDef[noCols]; // Points to the first column definition - + // Allocate statement handles for the table if (!queryOnly) { @@ -239,12 +217,12 @@ bool wxDbTable::initialize(wxDb *pwxDb, const wxString &tblName, const UWORD num // Allocate a separate statement handle for internal use if (SQLAllocStmt(hdbc, &hstmtInternal) != SQL_SUCCESS) pDb->DispAllErrors(henv, hdbc); - + // Set the cursor type for the statement handles cursorType = SQL_CURSOR_STATIC; - + if (SQLSetStmtOption(hstmtInternal, SQL_CURSOR_TYPE, cursorType) != SQL_SUCCESS) - { + { // Check to see if cursor type is supported pDb->GetNextError(henv, hdbc, hstmtInternal); if (! wxStrcmp(pDb->sqlState, wxT("01S02"))) // Option Value Changed @@ -296,7 +274,7 @@ bool wxDbTable::initialize(wxDb *pwxDb, const wxString &tblName, const UWORD num else cout << wxT("Cursor Type set to STATIC") << endl << endl; #endif - + if (!queryOnly) { // Set the cursor type for the INSERT statement handle @@ -309,7 +287,7 @@ bool wxDbTable::initialize(wxDb *pwxDb, const wxString &tblName, const UWORD num if (SQLSetStmtOption(hstmtUpdate, SQL_CURSOR_TYPE, SQL_CURSOR_FORWARD_ONLY) != SQL_SUCCESS) pDb->DispAllErrors(henv, hdbc, hstmtUpdate); } - + // Make the default cursor the active cursor hstmtDefault = GetNewCursor(FALSE,FALSE); wxASSERT(hstmtDefault); @@ -351,7 +329,7 @@ void wxDbTable::cleanup() if (!found) { wxString msg; - msg.Printf(wxT("Unable to find the tableID in the linked\nlist of tables in use.\n\n%s"),s); + msg.Printf(wxT("Unable to find the tableID in the linked\nlist of tables in use.\n\n%s"),s.c_str()); wxLogDebug (msg,wxT("NOTICE...")); } } @@ -411,6 +389,10 @@ ODBC 3.0 says to use this form if (hstmtCount) DeleteCursor(hstmtCount); + + if (m_hstmtGridQuery) + DeleteCursor(m_hstmtGridQuery); + } // wxDbTable::cleanup() @@ -423,11 +405,11 @@ bool wxDbTable::bindParams(bool forUpdate) wxASSERT(!queryOnly); if (queryOnly) return(FALSE); - + SWORD fSqlType = 0; UDWORD precision = 0; SWORD scale = 0; - + // Bind each column of the table that should be bound // to a parameter marker int i; @@ -469,7 +451,7 @@ bool wxDbTable::bindParams(bool forUpdate) case DB_DATA_TYPE_FLOAT: fSqlType = pDb->GetTypeInfFloat().FsqlType; precision = pDb->GetTypeInfFloat().Precision; - scale = pDb->GetTypeInfFloat().MaximumScale; + scale = pDb->GetTypeInfFloat().MaximumScale; // SQL Sybase Anywhere v5.5 returned a negative number for the // MaxScale. This caused ODBC to kick out an error on ibscale. // I check for this here and set the scale = precision. @@ -502,7 +484,7 @@ bool wxDbTable::bindParams(bool forUpdate) if (forUpdate) { if (SQLBindParameter(hstmtUpdate, colNo++, SQL_PARAM_INPUT, colDefs[i].SqlCtype, - fSqlType, precision, scale, (UCHAR*) colDefs[i].PtrDataObj, + fSqlType, precision, scale, (UCHAR*) colDefs[i].PtrDataObj, precision+1, &colDefs[i].CbValue) != SQL_SUCCESS) { return(pDb->DispAllErrors(henv, hdbc, hstmtUpdate)); @@ -511,14 +493,14 @@ bool wxDbTable::bindParams(bool forUpdate) else { if (SQLBindParameter(hstmtInsert, colNo++, SQL_PARAM_INPUT, colDefs[i].SqlCtype, - fSqlType, precision, scale, (UCHAR*) colDefs[i].PtrDataObj, + fSqlType, precision, scale, (UCHAR*) colDefs[i].PtrDataObj, precision+1,&colDefs[i].CbValue) != SQL_SUCCESS) { return(pDb->DispAllErrors(henv, hdbc, hstmtInsert)); } } } - + // Completed successfully return(TRUE); @@ -675,28 +657,13 @@ bool wxDbTable::query(int queryType, bool forUpdate, bool distinct, const wxStri BuildSelectStmt(sqlStmt, queryType, distinct); pDb->WriteSqlLog(sqlStmt); } -/* - This is the block of code that got added during the 2.2.1 merge with - the 2.2 main branch that somehow got added here when it should not have. - gt - - else - wxStrcpy(sqlStmt, pSqlStmt); - SQLFreeStmt(hstmt, SQL_CLOSE); - if (SQLExecDirect(hstmt, (UCHAR FAR *) sqlStmt, SQL_NTS) == SQL_SUCCESS) - return(TRUE); - else - { - pDb->DispAllErrors(henv, hdbc, hstmt); - return(FALSE); - } -*/ // Make sure the cursor is closed first if (!CloseCursor(hstmt)) return(FALSE); // Execute the SQL SELECT statement - int retcode; + int retcode; retcode = SQLExecDirect(hstmt, (UCHAR FAR *) (queryType == DB_SELECT_STATEMENT ? pSqlStmt.c_str() : sqlStmt.c_str()), SQL_NTS); if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO) return(pDb->DispAllErrors(henv, hdbc, hstmt)); @@ -714,11 +681,24 @@ bool wxDbTable::query(int queryType, bool forUpdate, bool distinct, const wxStri bool wxDbTable::Open(bool checkPrivileges, bool checkTableExists) { if (!pDb) - return FALSE; + return FALSE; int i; wxString sqlStmt; wxString s; +// int NumKeyCols=0; + + // Calculate the maximum size of the concatenated + // keys for use with wxDbGrid + m_keysize = 0; + for (i=0; i < noCols; i++) + { + if (colDefs[i].KeyField) + { +// NumKeyCols++; + m_keysize += colDefs[i].SzDataObj; + } + } s.Empty(); // Verify that the table exists in the database @@ -733,12 +713,12 @@ bool wxDbTable::Open(bool checkPrivileges, bool checkTableExists) else if (checkPrivileges) { // Verify the user has rights to access the table. - // Shortcut boolean evaluation to optimize out call to + // Shortcut boolean evaluation to optimize out call to // TablePrivileges // // Unfortunately this optimization doesn't seem to be // reliable! - if (// *(pDb->dbInf.accessibleTables) == 'N' && + if (// *(pDb->dbInf.accessibleTables) == 'N' && !pDb->TablePrivileges(tableName,wxT("SELECT"), pDb->GetUsername(), pDb->GetUsername(), tablePath)) s = wxT("Current logged in user does not have sufficient privileges to access this table.\n"); } @@ -764,14 +744,14 @@ bool wxDbTable::Open(bool checkPrivileges, bool checkTableExists) { if (!bindInsertParams()) // Inserts return(FALSE); - + if (!bindUpdateParams()) // Updates return(FALSE); } if (!bindCols(*hstmtDefault)) // Selects return(FALSE); - + if (!bindCols(hstmtInternal)) // Internal use only return(FALSE); @@ -783,14 +763,16 @@ bool wxDbTable::Open(bool checkPrivileges, bool checkTableExists) if (!queryOnly && noCols > 0) { bool needComma = FALSE; - sqlStmt.Printf(wxT("INSERT INTO %s ("), tableName.c_str()); + sqlStmt.Printf(wxT("INSERT INTO %s ("), + pDb->SQLTableName(tableName.c_str()).c_str()); for (i = 0; i < noCols; i++) { if (! colDefs[i].InsertAllowed) continue; if (needComma) sqlStmt += wxT(","); - sqlStmt += colDefs[i].ColName; + sqlStmt += pDb->SQLColumnName(colDefs[i].ColName); +// sqlStmt += colDefs[i].ColName; needComma = TRUE; } needComma = FALSE; @@ -809,17 +791,17 @@ bool wxDbTable::Open(bool checkPrivileges, bool checkTableExists) insertableCount++; } sqlStmt += wxT(")"); - + // Prepare the insert statement for execution - if (insertableCount) + if (insertableCount) { if (SQLPrepare(hstmtInsert, (UCHAR FAR *) sqlStmt.c_str(), SQL_NTS) != SQL_SUCCESS) return(pDb->DispAllErrors(henv, hdbc, hstmtInsert)); } - else + else insertable= FALSE; } - + // Completed successfully return(TRUE); @@ -913,7 +895,7 @@ bool wxDbTable::GetLast(void) wxFAIL_MSG(wxT("GetLast()::Backward scrolling cursors are not enabled for this instance of wxDbTable")); return FALSE; } - else + else return(getRec(SQL_FETCH_LAST)); } // wxDbTable::GetLast() @@ -934,11 +916,13 @@ void wxDbTable::BuildDeleteStmt(wxString &pSqlStmt, int typeOfDel, const wxStrin // delete all records from the database in this case. if (typeOfDel == DB_DEL_WHERE && (pWhereClause.Length() == 0)) { - pSqlStmt.Printf(wxT("DELETE FROM %s"), tableName.c_str()); + pSqlStmt.Printf(wxT("DELETE FROM %s"), + pDb->SQLTableName(tableName.c_str()).c_str()); return; } - pSqlStmt.Printf(wxT("DELETE FROM %s WHERE "), tableName.c_str()); + pSqlStmt.Printf(wxT("DELETE FROM %s WHERE "), + pDb->SQLTableName(tableName.c_str()).c_str()); // Append the WHERE clause to the SQL DELETE statement switch(typeOfDel) @@ -1020,10 +1004,12 @@ void wxDbTable::BuildSelectStmt(wxString &pSqlStmt, int typeOfSelect, bool disti // If joining tables, the base table column names must be qualified to avoid ambiguity if (appendFromClause || pDb->Dbms() == dbmsACCESS) { - pSqlStmt += queryTableName; + pSqlStmt += pDb->SQLTableName(queryTableName.c_str()); +// pSqlStmt += queryTableName; pSqlStmt += wxT("."); } - pSqlStmt += colDefs[i].ColName; + pSqlStmt += pDb->SQLColumnName(colDefs[i].ColName); +// pSqlStmt += colDefs[i].ColName; if (i + 1 < noCols) pSqlStmt += wxT(","); } @@ -1036,7 +1022,8 @@ void wxDbTable::BuildSelectStmt(wxString &pSqlStmt, int typeOfSelect, bool disti if (appendFromClause || pDb->Dbms() == dbmsACCESS) { pSqlStmt += wxT(","); - pSqlStmt += queryTableName; + pSqlStmt += pDb->SQLTableName(queryTableName); +// pSqlStmt += queryTableName; pSqlStmt += wxT(".ROWID"); } else @@ -1045,7 +1032,8 @@ void wxDbTable::BuildSelectStmt(wxString &pSqlStmt, int typeOfSelect, bool disti // Append the FROM tablename portion pSqlStmt += wxT(" FROM "); - pSqlStmt += queryTableName; + pSqlStmt += pDb->SQLTableName(queryTableName); +// pSqlStmt += queryTableName; // Sybase uses the HOLDLOCK keyword to lock a record during query. // The HOLDLOCK keyword follows the table name in the from clause. @@ -1132,7 +1120,8 @@ void wxDbTable::BuildUpdateStmt(wxString &pSqlStmt, int typeOfUpd, const wxStrin bool firstColumn = TRUE; - pSqlStmt.Printf(wxT("UPDATE %s SET "), tableName.Upper().c_str()); + pSqlStmt.Printf(wxT("UPDATE %s SET "), + pDb->SQLTableName(tableName.c_str()).c_str()); // Append a list of columns to be updated int i; @@ -1141,11 +1130,13 @@ void wxDbTable::BuildUpdateStmt(wxString &pSqlStmt, int typeOfUpd, const wxStrin // Only append Updateable columns if (colDefs[i].Updateable) { - if (! firstColumn) + if (!firstColumn) pSqlStmt += wxT(","); else firstColumn = FALSE; - pSqlStmt += colDefs[i].ColName; + + pSqlStmt += pDb->SQLColumnName(colDefs[i].ColName); +// pSqlStmt += colDefs[i].ColName; pSqlStmt += wxT(" = ?"); } } @@ -1225,10 +1216,12 @@ void wxDbTable::BuildWhereClause(wxString &pWhereClause, int typeOfWhere, // Concatenate where phrase for the column if (qualTableName.Length()) { - pWhereClause += qualTableName; + pWhereClause += pDb->SQLTableName(qualTableName); +// pWhereClause += qualTableName; pWhereClause += wxT("."); } - pWhereClause += colDefs[i].ColName; + pWhereClause += pDb->SQLColumnName(colDefs[i].ColName); +// pWhereClause += colDefs[i].ColName; if (useLikeComparison && (colDefs[i].SqlCtype == SQL_C_CHAR)) pWhereClause += wxT(" LIKE "); else @@ -1330,19 +1323,19 @@ bool wxDbTable::CreateTable(bool attemptDrop) switch(colDefs[i].DbDataType) { case DB_DATA_TYPE_VARCHAR: - cout << pDb->typeInfVarchar.TypeName << wxT("(") << colDefs[i].SzDataObj << wxT(")"); + cout << pDb->GetTypeInfVarchar().TypeName << wxT("(") << colDefs[i].SzDataObj << wxT(")"); break; case DB_DATA_TYPE_INTEGER: - cout << pDb->typeInfInteger.TypeName; + cout << pDb->GetTypeInfInteger().TypeName; break; case DB_DATA_TYPE_FLOAT: - cout << pDb->typeInfFloat.TypeName; + cout << pDb->GetTypeInfFloat().TypeName; break; case DB_DATA_TYPE_DATE: - cout << pDb->typeInfDate.TypeName; + cout << pDb->GetTypeInfDate().TypeName; break; case DB_DATA_TYPE_BLOB: - cout << pDb->typeInfBlob.TypeName; + cout << pDb->GetTypeInfBlob().TypeName; break; } cout << endl; @@ -1351,7 +1344,9 @@ bool wxDbTable::CreateTable(bool attemptDrop) // Build a CREATE TABLE string from the colDefs structure. bool needComma = FALSE; - sqlStmt.Printf(wxT("CREATE TABLE %s ("), tableName.c_str()); + + sqlStmt.Printf(wxT("CREATE TABLE %s ("), + pDb->SQLTableName(tableName.c_str()).c_str()); for (i = 0; i < noCols; i++) { @@ -1362,7 +1357,8 @@ bool wxDbTable::CreateTable(bool attemptDrop) if (needComma) sqlStmt += wxT(","); // Column Name - sqlStmt += colDefs[i].ColName; + sqlStmt += pDb->SQLColumnName(colDefs[i].ColName); +// sqlStmt += colDefs[i].ColName; sqlStmt += wxT(" "); // Column Type switch(colDefs[i].DbDataType) @@ -1395,6 +1391,7 @@ bool wxDbTable::CreateTable(bool attemptDrop) if (pDb->Dbms() == dbmsDB2 || pDb->Dbms() == dbmsMY_SQL || pDb->Dbms() == dbmsSYBASE_ASE || + pDb->Dbms() == dbmsINTERBASE || pDb->Dbms() == dbmsMS_SQL_SERVER) { if (colDefs[i].KeyField) @@ -1402,7 +1399,7 @@ bool wxDbTable::CreateTable(bool attemptDrop) sqlStmt += wxT(" NOT NULL"); } } - + needComma = TRUE; } // If there is a primary key defined, include it in the create statement @@ -1418,6 +1415,8 @@ bool wxDbTable::CreateTable(bool attemptDrop) { switch (pDb->Dbms()) { + case dbmsACCESS: + case dbmsINFORMIX: case dbmsSYBASE_ASA: case dbmsSYBASE_ASE: case dbmsMY_SQL: @@ -1433,10 +1432,12 @@ bool wxDbTable::CreateTable(bool attemptDrop) if (pDb->Dbms() == dbmsDB2) { wxASSERT_MSG((tableName && wxStrlen(tableName) <= 13), wxT("DB2 table/index names must be no longer than 13 characters in length.\n\nTruncating table name to 13 characters.")); - sqlStmt += tableName.substr(0, 13); + sqlStmt += pDb->SQLTableName(tableName.substr(0, 13).c_str()); +// sqlStmt += tableName.substr(0, 13); } else - sqlStmt += tableName; + sqlStmt += pDb->SQLTableName(tableName.c_str()); +// sqlStmt += tableName; sqlStmt += wxT("_PIDX PRIMARY KEY ("); break; @@ -1450,16 +1451,19 @@ bool wxDbTable::CreateTable(bool attemptDrop) { if (j++) // Multi part key, comma separate names sqlStmt += wxT(","); - sqlStmt += colDefs[i].ColName; + sqlStmt += pDb->SQLColumnName(colDefs[i].ColName); +// sqlStmt += colDefs[i].ColName; } } sqlStmt += wxT(")"); - if (pDb->Dbms() == dbmsSYBASE_ASA || + if (pDb->Dbms() == dbmsINFORMIX || + pDb->Dbms() == dbmsSYBASE_ASA || pDb->Dbms() == dbmsSYBASE_ASE) { sqlStmt += wxT(" CONSTRAINT "); - sqlStmt += tableName; + sqlStmt += pDb->SQLTableName(tableName); +// sqlStmt += tableName; sqlStmt += wxT("_PIDX"); } } @@ -1504,7 +1508,8 @@ bool wxDbTable::DropTable() wxString sqlStmt; - sqlStmt.Printf(wxT("DROP TABLE %s"), tableName.c_str()); + sqlStmt.Printf(wxT("DROP TABLE %s"), + pDb->SQLTableName(tableName.c_str()).c_str()); pDb->WriteSqlLog(sqlStmt); @@ -1512,22 +1517,19 @@ bool wxDbTable::DropTable() cout << endl << sqlStmt.c_str() << endl; #endif - - - RETCODE retcode = SQLExecDirect(hstmt, (UCHAR FAR *) sqlStmt.c_str(), SQL_NTS); if (retcode != SQL_SUCCESS) { // Check for "Base table not found" error and ignore - pDb->GetNextError(henv, hdbc, hstmt); + pDb->GetNextError(henv, hdbc, hstmt); if (wxStrcmp(pDb->sqlState, wxT("S0002")) /*&& - wxStrcmp(pDb->sqlState, wxT("S1000"))*/) // "Base table not found" + wxStrcmp(pDb->sqlState, wxT("S1000"))*/) // "Base table not found" { // Check for product specific error codes if (!((pDb->Dbms() == dbmsSYBASE_ASA && !wxStrcmp(pDb->sqlState,wxT("42000"))) || // 5.x (and lower?) - (pDb->Dbms() == dbmsSYBASE_ASE && !wxStrcmp(pDb->sqlState,wxT("37000"))) || + (pDb->Dbms() == dbmsSYBASE_ASE && !wxStrcmp(pDb->sqlState,wxT("37000"))) || (pDb->Dbms() == dbmsPERVASIVE_SQL && !wxStrcmp(pDb->sqlState,wxT("S1000"))) || // Returns an S1000 then an S0002 - (pDb->Dbms() == dbmsPOSTGRES && !wxStrcmp(pDb->sqlState,wxT("08S01"))))) + (pDb->Dbms() == dbmsPOSTGRES && !wxStrcmp(pDb->sqlState,wxT("08S01"))))) { pDb->DispNextError(); pDb->DispAllErrors(henv, hdbc, hstmt); @@ -1586,7 +1588,7 @@ bool wxDbTable::CreateIndex(const wxString &idxName, bool unique, UWORD noIdxCol if (!found) j++; } - + if (found) { ok = pDb->ModifyColumn(tableName, pIdxDefs[i].ColName, @@ -1613,36 +1615,43 @@ bool wxDbTable::CreateIndex(const wxString &idxName, bool unique, UWORD noIdxCol return(FALSE); } } - + // Build a CREATE INDEX statement sqlStmt = wxT("CREATE "); if (unique) sqlStmt += wxT("UNIQUE "); - + sqlStmt += wxT("INDEX "); - sqlStmt += idxName; + sqlStmt += pDb->SQLTableName(idxName); sqlStmt += wxT(" ON "); - sqlStmt += tableName; + + sqlStmt += pDb->SQLTableName(tableName); +// sqlStmt += tableName; sqlStmt += wxT(" ("); - + // Append list of columns making up index int i; for (i = 0; i < noIdxCols; i++) { - sqlStmt += pIdxDefs[i].ColName; - /* Postgres doesn't cope with ASC */ - if (pDb->Dbms() != dbmsPOSTGRES) + sqlStmt += pDb->SQLColumnName(pIdxDefs[i].ColName); +// sqlStmt += pIdxDefs[i].ColName; + + // Postgres and SQL Server 7 do not support the ASC/DESC keywords for index columns + if (!((pDb->Dbms() == dbmsMS_SQL_SERVER) && (strncmp(pDb->dbInf.dbmsVer,"07",2)==0)) && + !(pDb->Dbms() == dbmsPOSTGRES)) { if (pIdxDefs[i].Ascending) sqlStmt += wxT(" ASC"); else sqlStmt += wxT(" DESC"); } + else + wxASSERT_MSG(pIdxDefs[i].Ascending, "Datasource does not support DESCending index columns"); if ((i + 1) < noIdxCols) sqlStmt += wxT(","); } - + // Append closing parentheses sqlStmt += wxT(")"); @@ -1685,12 +1694,17 @@ bool wxDbTable::DropIndex(const wxString &idxName) if (pDb->Dbms() == dbmsACCESS || pDb->Dbms() == dbmsMY_SQL || pDb->Dbms() == dbmsDBASE /*|| Paradox needs this syntax too when we add support*/) - sqlStmt.Printf(wxT("DROP INDEX %s ON %s"),idxName.c_str(), tableName.c_str()); + sqlStmt.Printf(wxT("DROP INDEX %s ON %s"), + pDb->SQLTableName(idxName.c_str()).c_str(), + pDb->SQLTableName(tableName.c_str()).c_str()); else if ((pDb->Dbms() == dbmsMS_SQL_SERVER) || (pDb->Dbms() == dbmsSYBASE_ASE)) - sqlStmt.Printf(wxT("DROP INDEX %s.%s"),tableName.c_str(), idxName.c_str()); + sqlStmt.Printf(wxT("DROP INDEX %s.%s"), + pDb->SQLTableName(tableName.c_str()).c_str(), + pDb->SQLTableName(idxName.c_str()).c_str()); else - sqlStmt.Printf(wxT("DROP INDEX %s"),idxName.c_str()); + sqlStmt.Printf(wxT("DROP INDEX %s"), + pDb->SQLTableName(idxName.c_str()).c_str()); pDb->WriteSqlLog(sqlStmt); @@ -1708,6 +1722,7 @@ bool wxDbTable::DropIndex(const wxString &idxName) if (!((pDb->Dbms() == dbmsSYBASE_ASA && !wxStrcmp(pDb->sqlState,wxT("42000"))) || // v5.x (and lower?) (pDb->Dbms() == dbmsSYBASE_ASE && !wxStrcmp(pDb->sqlState,wxT("37000"))) || (pDb->Dbms() == dbmsMS_SQL_SERVER && !wxStrcmp(pDb->sqlState,wxT("S1000"))) || + (pDb->Dbms() == dbmsINTERBASE && !wxStrcmp(pDb->sqlState,wxT("S1000"))) || (pDb->Dbms() == dbmsSYBASE_ASE && !wxStrcmp(pDb->sqlState,wxT("S0002"))) || // Base table not found (pDb->Dbms() == dbmsMY_SQL && !wxStrcmp(pDb->sqlState,wxT("42S12"))) || // tested by Christopher Ludwik Marino-Cebulski using v3.23.21beta (pDb->Dbms() == dbmsPOSTGRES && !wxStrcmp(pDb->sqlState,wxT("08S01"))) @@ -1926,7 +1941,7 @@ bool wxDbTable::DeleteMatching(void) /********** wxDbTable::IsColNull() **********/ -bool wxDbTable::IsColNull(UWORD colNo) +bool wxDbTable::IsColNull(UWORD colNo) const { /* This logic is just not right. It would indicate TRUE @@ -2096,8 +2111,15 @@ void wxDbTable::SetColDefs(UWORD index, const wxString &fieldName, int dataType, if (fieldName.Length() > (unsigned int) DB_MAX_COLUMN_NAME_LEN) { - wxStrncpy (colDefs[index].ColName, fieldName, DB_MAX_COLUMN_NAME_LEN); + wxStrncpy(colDefs[index].ColName, fieldName, DB_MAX_COLUMN_NAME_LEN); colDefs[index].ColName[DB_MAX_COLUMN_NAME_LEN] = 0; + +#ifdef __WXDEBUG__ + wxString tmpMsg; + tmpMsg.Printf(_T("Column name '%s' is too long. Truncated to '%s'."), + fieldName.c_str(),colDefs[index].ColName); + wxFAIL_MSG(tmpMsg); +#endif // __WXDEBUG__ } else wxStrcpy(colDefs[index].ColName, fieldName); @@ -2121,7 +2143,7 @@ void wxDbTable::SetColDefs(UWORD index, const wxString &fieldName, int dataType, } colDefs[index].Null = FALSE; - + } // wxDbTable::SetColDefs() @@ -2134,7 +2156,7 @@ wxDbColDataPtr* wxDbTable::SetColDefs(wxDbColInf *pColInfs, UWORD numCols) if (pColInfs) { UWORD index; - + pColDataPtrs = new wxDbColDataPtr[numCols+1]; for (index = 0; index < numCols; index++) @@ -2175,7 +2197,7 @@ wxDbColDataPtr* wxDbTable::SetColDefs(wxDbColInf *pColInfs, UWORD numCols) pColDataPtrs[index].PtrDataObj = new double; pColDataPtrs[index].SzDataObj = sizeof(double); pColDataPtrs[index].SqlCtype = SQL_C_DOUBLE; - } + } break; case DB_DATA_TYPE_DATE: pColDataPtrs[index].PtrDataObj = new TIMESTAMP_STRUCT; @@ -2183,8 +2205,7 @@ wxDbColDataPtr* wxDbTable::SetColDefs(wxDbColInf *pColInfs, UWORD numCols) pColDataPtrs[index].SqlCtype = SQL_C_TIMESTAMP; break; case DB_DATA_TYPE_BLOB: - int notSupportedYet = 0; - wxASSERT_MSG(notSupportedYet, wxT("This form of ::SetColDefs() cannot be used with BLOB columns")); + wxFAIL_MSG(wxT("This form of ::SetColDefs() cannot be used with BLOB columns")); pColDataPtrs[index].PtrDataObj = /*BLOB ADDITION NEEDED*/NULL; pColDataPtrs[index].SzDataObj = /*BLOB ADDITION NEEDED*/sizeof(void *); pColDataPtrs[index].SqlCtype = SQL_VARBINARY; @@ -2194,7 +2215,7 @@ wxDbColDataPtr* wxDbTable::SetColDefs(wxDbColInf *pColInfs, UWORD numCols) SetColDefs (index,pColInfs[index].colName,pColInfs[index].dbDataType, pColDataPtrs[index].PtrDataObj, pColDataPtrs[index].SqlCtype, pColDataPtrs[index].SzDataObj); else { - // Unable to build all the column definitions, as either one of + // Unable to build all the column definitions, as either one of // the calls to "new" failed above, or there was a BLOB field // to have a column definition for. If BLOBs are to be used, // the other form of ::SetColDefs() must be used, as it is impossible @@ -2232,7 +2253,8 @@ ULONG wxDbTable::Count(const wxString &args) sqlStmt = wxT("SELECT COUNT("); sqlStmt += args; sqlStmt += wxT(") FROM "); - sqlStmt += queryTableName; + sqlStmt += pDb->SQLTableName(queryTableName); +// sqlStmt += queryTableName; #if wxODBC_BACKWARD_COMPATABILITY if (from && wxStrlen(from)) #else @@ -2324,7 +2346,8 @@ bool wxDbTable::Refresh(void) // based on the key fields. if (SQLGetData(hstmt, (UWORD)(noCols+1), SQL_C_CHAR, (UCHAR*) rowid, wxDB_ROWID_LEN, &cb) == SQL_SUCCESS) { - whereClause += queryTableName; + whereClause += pDb->SQLTableName(queryTableName); +// whereClause += queryTableName; whereClause += wxT(".ROWID = '"); whereClause += rowid; whereClause += wxT("'"); @@ -2423,7 +2446,7 @@ HSTMT *wxDbTable::GetNewCursor(bool setCursor, bool bindColumns) if (bindColumns) { - if(!bindCols(*newHSTMT)) + if (!bindCols(*newHSTMT)) { delete newHSTMT; return(0); @@ -2449,7 +2472,7 @@ bool wxDbTable::DeleteCursor(HSTMT *hstmtDel) /* ODBC 3.0 says to use this form if (SQLFreeHandle(*hstmtDel, SQL_DROP) != SQL_SUCCESS) - + */ if (SQLFreeStmt(*hstmtDel, SQL_DROP) != SQL_SUCCESS) { @@ -2463,5 +2486,228 @@ ODBC 3.0 says to use this form } // wxDbTable::DeleteCursor() +////////////////////////////////////////////////////////////// +// wxDbGrid support functions +////////////////////////////////////////////////////////////// + +void wxDbTable::SetRowMode(const rowmode_t rowmode) +{ + if (!m_hstmtGridQuery) + { + m_hstmtGridQuery = GetNewCursor(FALSE,FALSE); + if (!bindCols(*m_hstmtGridQuery)) + return; + } + + m_rowmode = rowmode; + switch (m_rowmode) + { + case WX_ROW_MODE_QUERY: + SetCursor(m_hstmtGridQuery); + break; + case WX_ROW_MODE_INDIVIDUAL: + SetCursor(hstmtDefault); + break; + default: + assert(0); + } +} // wxDbTable::SetRowMode() + + +wxVariant wxDbTable::GetCol(const int colNo) const +{ + wxVariant val; + if ((colNo < noCols) && (!IsColNull(colNo))) + { + switch (colDefs[colNo].SqlCtype) + { + case SQL_CHAR: + case SQL_VARCHAR: + val = (wxChar *)(colDefs[colNo].PtrDataObj); + break; + case SQL_C_LONG: + case SQL_C_SLONG: + val = *(long *)(colDefs[colNo].PtrDataObj); + break; + case SQL_C_SHORT: + case SQL_C_SSHORT: + val = (long int )(*(short *)(colDefs[colNo].PtrDataObj)); + break; + case SQL_C_ULONG: + val = (long)(*(unsigned long *)(colDefs[colNo].PtrDataObj)); + break; + case SQL_C_TINYINT: + val = (long)(*(char *)(colDefs[colNo].PtrDataObj)); + break; + case SQL_C_UTINYINT: + val = (long)(*(unsigned char *)(colDefs[colNo].PtrDataObj)); + break; + case SQL_C_USHORT: + val = (long)(*(UWORD *)(colDefs[colNo].PtrDataObj)); + break; + case SQL_C_DATE: + val = (DATE_STRUCT *)(colDefs[colNo].PtrDataObj); + break; + case SQL_C_TIME: + val = (TIME_STRUCT *)(colDefs[colNo].PtrDataObj); + break; + case SQL_C_TIMESTAMP: + val = (TIMESTAMP_STRUCT *)(colDefs[colNo].PtrDataObj); + break; + case SQL_C_DOUBLE: + val = *(double *)(colDefs[colNo].PtrDataObj); + break; + default: + assert(0); + } + } + return val; +} // wxDbTable::GetCol() + + +void csstrncpyt(char *s, const char *t, int n) +{ + while ((*s++ = *t++) && --n) + {}; + + *s = '\0'; +} + +void wxDbTable::SetCol(const int colNo, const wxVariant val) +{ + //FIXME: Add proper wxDateTime support to wxVariant.. + wxDateTime dateval; + + SetColNull(colNo, val.IsNull()); + + if (!val.IsNull()) + { + if ((colDefs[colNo].SqlCtype == SQL_C_DATE) + || (colDefs[colNo].SqlCtype == SQL_C_TIME) + || (colDefs[colNo].SqlCtype == SQL_C_TIMESTAMP)) + { + //Returns null if invalid! + if (!dateval.ParseDate(val.GetString())) + SetColNull(colNo, TRUE); + } + + switch (colDefs[colNo].SqlCtype) + { + case SQL_CHAR: + case SQL_VARCHAR: + csstrncpyt((char *)(colDefs[colNo].PtrDataObj), + val.GetString().c_str(), + colDefs[colNo].SzDataObj-1); + break; + case SQL_C_LONG: + case SQL_C_SLONG: + *(long *)(colDefs[colNo].PtrDataObj) = val; + break; + case SQL_C_SHORT: + case SQL_C_SSHORT: + *(short *)(colDefs[colNo].PtrDataObj) = val.GetLong(); + break; + case SQL_C_ULONG: + *(unsigned long *)(colDefs[colNo].PtrDataObj) = val.GetLong(); + break; + case SQL_C_TINYINT: + *(char *)(colDefs[colNo].PtrDataObj) = val.GetChar(); + break; + case SQL_C_UTINYINT: + *(unsigned char *)(colDefs[colNo].PtrDataObj) = val.GetChar(); + break; + case SQL_C_USHORT: + *(unsigned short *)(colDefs[colNo].PtrDataObj) = val.GetLong(); + break; + //FIXME: Add proper wxDateTime support to wxVariant.. + case SQL_C_DATE: + { + DATE_STRUCT *dataptr = + (DATE_STRUCT *)colDefs[colNo].PtrDataObj; + + dataptr->year = dateval.GetYear(); + dataptr->month = dateval.GetMonth()+1; + dataptr->day = dateval.GetDay(); + } + break; + case SQL_C_TIME: + { + TIME_STRUCT *dataptr = + (TIME_STRUCT *)colDefs[colNo].PtrDataObj; + + dataptr->hour = dateval.GetHour(); + dataptr->minute = dateval.GetMinute(); + dataptr->second = dateval.GetSecond(); + } + break; + case SQL_C_TIMESTAMP: + { + TIMESTAMP_STRUCT *dataptr = + (TIMESTAMP_STRUCT *)colDefs[colNo].PtrDataObj; + dataptr->year = dateval.GetYear(); + dataptr->month = dateval.GetMonth()+1; + dataptr->day = dateval.GetDay(); + + dataptr->hour = dateval.GetHour(); + dataptr->minute = dateval.GetMinute(); + dataptr->second = dateval.GetSecond(); + } + break; + case SQL_C_DOUBLE: + *(double *)(colDefs[colNo].PtrDataObj) = val; + break; + default: + assert(0); + } // switch + } // if (!val.IsNull()) +} // wxDbTable::SetCol() + + +GenericKey wxDbTable::GetKey() +{ + void *blk; + wxChar *blkptr; + + blk = malloc(m_keysize); + blkptr = (wxChar *) blk; + + int i; + for (i=0; i < noCols; i++) + { + if (colDefs[i].KeyField) + { + memcpy(blkptr,colDefs[i].PtrDataObj, colDefs[i].SzDataObj); + blkptr += colDefs[i].SzDataObj; + } + } + + GenericKey k = GenericKey(blk, m_keysize); + free(blk); + + return k; +} // wxDbTable::GetKey() + + +void wxDbTable::SetKey(const GenericKey& k) +{ + void *blk; + wxChar *blkptr; + + blk = k.GetBlk(); + blkptr = (wxChar *)blk; + + int i; + for (i=0; i < noCols; i++) + { + if (colDefs[i].KeyField) + { + SetColNull(i, FALSE); + memcpy(colDefs[i].PtrDataObj, blkptr, colDefs[i].SzDataObj); + blkptr += colDefs[i].SzDataObj; + } + } +} // wxDbTable::SetKey() + + #endif // wxUSE_ODBC