X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/4888e623a6869c6af62cfe42da6303f9c8870585..a6de86fa530d95b6f30e0349e81de8b8692b348f:/src/common/dbtable.cpp diff --git a/src/common/dbtable.cpp b/src/common/dbtable.cpp index fcdbf3e1b4..c5482f8a69 100644 --- a/src/common/dbtable.cpp +++ b/src/common/dbtable.cpp @@ -24,7 +24,8 @@ // SYNOPSIS START // SYNOPSIS STOP */ -#ifdef __GNUG__ + +#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA) #pragma implementation "dbtable.h" #endif @@ -48,9 +49,6 @@ #include "wx/object.h" #include "wx/list.h" #include "wx/utils.h" - #if wxUSE_GUI - #include "wx/msgdlg.h" - #endif #include "wx/log.h" #endif #include "wx/filefn.h" @@ -60,7 +58,6 @@ #include #include #include -//#include #include "wx/dbtable.h" @@ -83,6 +80,16 @@ ULONG lastTableID = 0; #endif +void csstrncpyt(wxChar *target, const wxChar *source, int n) +{ + while ( (*target++ = *source++) != '\0' && --n ) + ; + + *target = '\0'; +} + + + /********** wxDbColDef::wxDbColDef() Constructor **********/ wxDbColDef::wxDbColDef() { @@ -318,17 +325,17 @@ void wxDbTable::cleanup() bool found = FALSE; wxNode *pNode; - pNode = TablesInUse.First(); + pNode = TablesInUse.GetFirst(); while (pNode && !found) { - if (((wxTablesInUse *)pNode->Data())->tableID == tableID) + if (((wxTablesInUse *)pNode->GetData())->tableID == tableID) { found = TRUE; if (!TablesInUse.DeleteNode(pNode)) wxLogDebug (s,wxT("Unable to delete node!")); } else - pNode = pNode->Next(); + pNode = pNode->GetNext(); } if (!found) { @@ -411,7 +418,7 @@ bool wxDbTable::bindParams(bool forUpdate) return(FALSE); SWORD fSqlType = 0; - UDWORD precision = 0; + SDWORD precision = 0; SWORD scale = 0; // Bind each column of the table that should be bound @@ -477,7 +484,7 @@ bool wxDbTable::bindParams(bool forUpdate) break; case DB_DATA_TYPE_BLOB: fSqlType = pDb->GetTypeInfBlob().FsqlType; - precision = 50000; + precision = -1; scale = 0; if (colDefs[i].Null) colDefs[i].CbValue = SQL_NULL_DATA; @@ -528,15 +535,16 @@ bool wxDbTable::bindUpdateParams(void) /********** wxDbTable::bindCols() **********/ bool wxDbTable::bindCols(HSTMT cursor) { + static SDWORD cb; + // Bind each column of the table to a memory address for fetching data UWORD i; for (i = 0; i < noCols; i++) { + cb = colDefs[i].CbValue; if (SQLBindCol(cursor, (UWORD)(i+1), colDefs[i].SqlCtype, (UCHAR*) colDefs[i].PtrDataObj, - colDefs[i].SzDataObj, &colDefs[i].CbValue ) != SQL_SUCCESS) - { + colDefs[i].SzDataObj, &cb ) != SQL_SUCCESS) return (pDb->DispAllErrors(henv, hdbc, cursor)); - } } // Completed successfully @@ -606,7 +614,7 @@ bool wxDbTable::execDelete(const wxString &pSqlStmt) RETCODE retcode; // Execute the DELETE statement - retcode = SQLExecDirect(hstmtDelete, (UCHAR FAR *) pSqlStmt.c_str(), SQL_NTS); + retcode = SQLExecDirect(hstmtDelete, (SQLTCHAR FAR *) pSqlStmt.c_str(), SQL_NTS); if (retcode == SQL_SUCCESS || retcode == SQL_NO_DATA_FOUND || @@ -628,7 +636,7 @@ bool wxDbTable::execUpdate(const wxString &pSqlStmt) RETCODE retcode; // Execute the UPDATE statement - retcode = SQLExecDirect(hstmtUpdate, (UCHAR FAR *) pSqlStmt.c_str(), SQL_NTS); + retcode = SQLExecDirect(hstmtUpdate, (SQLTCHAR FAR *) pSqlStmt.c_str(), SQL_NTS); if (retcode == SQL_SUCCESS || retcode == SQL_NO_DATA_FOUND || @@ -637,6 +645,37 @@ bool wxDbTable::execUpdate(const wxString &pSqlStmt) // Record updated successfully return(TRUE); } + else if (retcode == SQL_NEED_DATA) + { + PTR pParmID; + retcode = SQLParamData(hstmtUpdate, &pParmID); + while (retcode == SQL_NEED_DATA) + { + // Find the parameter + int i; + for (i=0; i < noCols; i++) + { + if (colDefs[i].PtrDataObj == pParmID) + { + // We found it. Store the parameter. + retcode = SQLPutData(hstmtUpdate, pParmID, colDefs[i].SzDataObj); + if (retcode != SQL_SUCCESS) + { + pDb->DispNextError(); + return pDb->DispAllErrors(henv, hdbc, hstmtUpdate); + } + break; + } + } + } + if (retcode == SQL_SUCCESS || + retcode == SQL_NO_DATA_FOUND || + retcode == SQL_SUCCESS_WITH_INFO) + { + // Record updated successfully + return(TRUE); + } + } // Problem updating record return(pDb->DispAllErrors(henv, hdbc, hstmtUpdate)); @@ -668,7 +707,7 @@ bool wxDbTable::query(int queryType, bool forUpdate, bool distinct, const wxStri // Execute the SQL SELECT statement int retcode; - retcode = SQLExecDirect(hstmt, (UCHAR FAR *) (queryType == DB_SELECT_STATEMENT ? pSqlStmt.c_str() : sqlStmt.c_str()), SQL_NTS); + retcode = SQLExecDirect(hstmt, (SQLTCHAR 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)); @@ -799,7 +838,7 @@ bool wxDbTable::Open(bool checkPrivileges, bool checkTableExists) // Prepare the insert statement for execution if (insertableCount) { - if (SQLPrepare(hstmtInsert, (UCHAR FAR *) sqlStmt.c_str(), SQL_NTS) != SQL_SUCCESS) + if (SQLPrepare(hstmtInsert, (SQLTCHAR FAR *) sqlStmt.c_str(), SQL_NTS) != SQL_SUCCESS) return(pDb->DispAllErrors(henv, hdbc, hstmtInsert)); } else @@ -1003,17 +1042,17 @@ void wxDbTable::BuildSelectStmt(wxString &pSqlStmt, int typeOfSelect, bool disti // Add the column list int i; + wxString tStr; for (i = 0; i < noCols; i++) { + tStr = colDefs[i].ColName; // If joining tables, the base table column names must be qualified to avoid ambiguity - if (appendFromClause || pDb->Dbms() == dbmsACCESS) + if ((appendFromClause || pDb->Dbms() == dbmsACCESS) && !tStr.Find(wxT('.'))) { pSqlStmt += pDb->SQLTableName(queryTableName.c_str()); -// pSqlStmt += queryTableName; pSqlStmt += wxT("."); } pSqlStmt += pDb->SQLColumnName(colDefs[i].ColName); -// pSqlStmt += colDefs[i].ColName; if (i + 1 < noCols) pSqlStmt += wxT(","); } @@ -1202,56 +1241,59 @@ void wxDbTable::BuildWhereClause(wxString &pWhereClause, int typeOfWhere, wxString colValue; // Loop through the columns building a where clause as you go - int i; - for (i = 0; i < noCols; i++) + int colNo; + for (colNo = 0; colNo < noCols; colNo++) { // Determine if this column should be included in the WHERE clause - if ((typeOfWhere == DB_WHERE_KEYFIELDS && colDefs[i].KeyField) || - (typeOfWhere == DB_WHERE_MATCHING && (!IsColNull(i)))) + if ((typeOfWhere == DB_WHERE_KEYFIELDS && colDefs[colNo].KeyField) || + (typeOfWhere == DB_WHERE_MATCHING && (!IsColNull(colNo)))) { // Skip over timestamp columns - if (colDefs[i].SqlCtype == SQL_C_TIMESTAMP) + if (colDefs[colNo].SqlCtype == SQL_C_TIMESTAMP) continue; // If there is more than 1 column, join them with the keyword "AND" if (moreThanOneColumn) pWhereClause += wxT(" AND "); else moreThanOneColumn = TRUE; + // Concatenate where phrase for the column - if (qualTableName.Length()) + wxString tStr = colDefs[colNo].ColName; + + if (qualTableName.Length() && !tStr.Find(wxT('.'))) { pWhereClause += pDb->SQLTableName(qualTableName); -// pWhereClause += qualTableName; pWhereClause += wxT("."); } - pWhereClause += pDb->SQLColumnName(colDefs[i].ColName); -// pWhereClause += colDefs[i].ColName; - if (useLikeComparison && (colDefs[i].SqlCtype == SQL_C_CHAR)) + pWhereClause += pDb->SQLColumnName(colDefs[colNo].ColName); + + if (useLikeComparison && (colDefs[colNo].SqlCtype == SQL_C_CHAR)) pWhereClause += wxT(" LIKE "); else pWhereClause += wxT(" = "); - switch(colDefs[i].SqlCtype) + + switch(colDefs[colNo].SqlCtype) { case SQL_C_CHAR: - colValue.Printf(wxT("'%s'"), (UCHAR FAR *) colDefs[i].PtrDataObj); + colValue.Printf(wxT("'%s'"), (UCHAR FAR *) colDefs[colNo].PtrDataObj); break; case SQL_C_SSHORT: - colValue.Printf(wxT("%hi"), *((SWORD *) colDefs[i].PtrDataObj)); + colValue.Printf(wxT("%hi"), *((SWORD *) colDefs[colNo].PtrDataObj)); break; case SQL_C_USHORT: - colValue.Printf(wxT("%hu"), *((UWORD *) colDefs[i].PtrDataObj)); + colValue.Printf(wxT("%hu"), *((UWORD *) colDefs[colNo].PtrDataObj)); break; case SQL_C_SLONG: - colValue.Printf(wxT("%li"), *((SDWORD *) colDefs[i].PtrDataObj)); + colValue.Printf(wxT("%li"), *((SDWORD *) colDefs[colNo].PtrDataObj)); break; case SQL_C_ULONG: - colValue.Printf(wxT("%lu"), *((UDWORD *) colDefs[i].PtrDataObj)); + colValue.Printf(wxT("%lu"), *((UDWORD *) colDefs[colNo].PtrDataObj)); break; case SQL_C_FLOAT: - colValue.Printf(wxT("%.6f"), *((SFLOAT *) colDefs[i].PtrDataObj)); + colValue.Printf(wxT("%.6f"), *((SFLOAT *) colDefs[colNo].PtrDataObj)); break; case SQL_C_DOUBLE: - colValue.Printf(wxT("%.6f"), *((SDOUBLE *) colDefs[i].PtrDataObj)); + colValue.Printf(wxT("%.6f"), *((SDOUBLE *) colDefs[colNo].PtrDataObj)); break; } pWhereClause += colValue; @@ -1384,7 +1426,8 @@ bool wxDbTable::CreateTable(bool attemptDrop) break; } // For varchars, append the size of the string - if (colDefs[i].DbDataType == DB_DATA_TYPE_VARCHAR)// || + if (colDefs[i].DbDataType == DB_DATA_TYPE_VARCHAR && + (pDb->Dbms() != dbmsMY_SQL || pDb->GetTypeInfVarchar().TypeName != _T("text")))// || // colDefs[i].DbDataType == DB_DATA_TYPE_BLOB) { wxString s; @@ -1415,7 +1458,8 @@ bool wxDbTable::CreateTable(bool attemptDrop) break; } } - if (j && pDb->Dbms() != dbmsDBASE) // Found a keyfield + if ( j && (pDb->Dbms() != dbmsDBASE) + && (pDb->Dbms() != dbmsXBASE_SEQUITER) ) // Found a keyfield { switch (pDb->Dbms()) { @@ -1456,7 +1500,14 @@ bool wxDbTable::CreateTable(bool attemptDrop) if (j++) // Multi part key, comma separate names sqlStmt += wxT(","); sqlStmt += pDb->SQLColumnName(colDefs[i].ColName); -// sqlStmt += colDefs[i].ColName; + + if (pDb->Dbms() == dbmsMY_SQL && + colDefs[i].DbDataType == DB_DATA_TYPE_VARCHAR) + { + wxString s; + s.Printf(wxT("(%d)"), colDefs[i].SzDataObj); + sqlStmt += s; + } } } sqlStmt += wxT(")"); @@ -1481,7 +1532,7 @@ bool wxDbTable::CreateTable(bool attemptDrop) #endif // Execute the CREATE TABLE statement - RETCODE retcode = SQLExecDirect(hstmt, (UCHAR FAR *) sqlStmt.c_str(), SQL_NTS); + RETCODE retcode = SQLExecDirect(hstmt, (SQLTCHAR FAR *) sqlStmt.c_str(), SQL_NTS); if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO) { pDb->DispAllErrors(henv, hdbc, hstmt); @@ -1521,7 +1572,7 @@ bool wxDbTable::DropTable() cout << endl << sqlStmt.c_str() << endl; #endif - RETCODE retcode = SQLExecDirect(hstmt, (UCHAR FAR *) sqlStmt.c_str(), SQL_NTS); + RETCODE retcode = SQLExecDirect(hstmt, (SQLTCHAR FAR *) sqlStmt.c_str(), SQL_NTS); if (retcode != SQL_SUCCESS) { // Check for "Base table not found" error and ignore @@ -1601,11 +1652,14 @@ bool wxDbTable::CreateIndex(const wxString &idxName, bool unique, UWORD noIdxCol if (!ok) { + #if 0 + // retcode is not used wxODBC_ERRORS retcode; // Oracle returns a DB_ERR_GENERAL_ERROR if the column is already // defined to be NOT NULL, but reportedly MySQL doesn't mind. // This line is just here for debug checking of the value retcode = (wxODBC_ERRORS)pDb->DB_STATUS; + #endif } } else @@ -1640,8 +1694,28 @@ bool wxDbTable::CreateIndex(const wxString &idxName, bool unique, UWORD noIdxCol sqlStmt += pDb->SQLColumnName(pIdxDefs[i].ColName); // sqlStmt += pIdxDefs[i].ColName; + // MySQL requires a key length on VARCHAR keys + if ( pDb->Dbms() == dbmsMY_SQL ) + { + // Find the details on this column + int j; + for ( j = 0; j < noCols; ++j ) + { + if ( wxStrcmp( pIdxDefs[i].ColName, colDefs[j].ColName ) == 0 ) + { + break; + } + } + if ( colDefs[j].DbDataType == DB_DATA_TYPE_VARCHAR) + { + wxString s; + s.Printf(wxT("(%d)"), colDefs[i].SzDataObj); + sqlStmt += s; + } + } + // 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)) && + if (!((pDb->Dbms() == dbmsMS_SQL_SERVER) && (wxStrncmp(pDb->dbInf.dbmsVer,_T("07"),2)==0)) && !(pDb->Dbms() == dbmsPOSTGRES)) { if (pIdxDefs[i].Ascending) @@ -1650,7 +1724,7 @@ bool wxDbTable::CreateIndex(const wxString &idxName, bool unique, UWORD noIdxCol sqlStmt += wxT(" DESC"); } else - wxASSERT_MSG(pIdxDefs[i].Ascending, "Datasource does not support DESCending index columns"); + wxASSERT_MSG(pIdxDefs[i].Ascending, _T("Datasource does not support DESCending index columns")); if ((i + 1) < noIdxCols) sqlStmt += wxT(","); @@ -1666,7 +1740,7 @@ bool wxDbTable::CreateIndex(const wxString &idxName, bool unique, UWORD noIdxCol #endif // Execute the CREATE INDEX statement - if (SQLExecDirect(hstmt, (UCHAR FAR *) sqlStmt.c_str(), SQL_NTS) != SQL_SUCCESS) + if (SQLExecDirect(hstmt, (SQLTCHAR FAR *) sqlStmt.c_str(), SQL_NTS) != SQL_SUCCESS) { pDb->DispAllErrors(henv, hdbc, hstmt); pDb->RollbackTrans(); @@ -1702,7 +1776,8 @@ bool wxDbTable::DropIndex(const wxString &idxName) 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)) + (pDb->Dbms() == dbmsSYBASE_ASE) || + (pDb->Dbms() == dbmsXBASE_SEQUITER)) sqlStmt.Printf(wxT("DROP INDEX %s.%s"), pDb->SQLTableName(tableName.c_str()).c_str(), pDb->SQLTableName(idxName.c_str()).c_str()); @@ -1716,7 +1791,7 @@ bool wxDbTable::DropIndex(const wxString &idxName) cout << endl << sqlStmt.c_str() << endl; #endif - if (SQLExecDirect(hstmt, (UCHAR FAR *) sqlStmt.c_str(), SQL_NTS) != SQL_SUCCESS) + if (SQLExecDirect(hstmt, (SQLTCHAR FAR *) sqlStmt.c_str(), SQL_NTS) != SQL_SUCCESS) { // Check for "Index not found" error and ignore pDb->GetNextError(henv, hdbc, hstmt); @@ -1799,7 +1874,8 @@ int wxDbTable::Insert(void) // Insert the record by executing the already prepared insert statement RETCODE retcode; retcode=SQLExecute(hstmtInsert); - if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO) + if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO && + retcode != SQL_NEED_DATA) { // Check to see if integrity constraint was violated pDb->GetNextError(henv, hdbc, hstmtInsert); @@ -1812,6 +1888,31 @@ int wxDbTable::Insert(void) return(DB_FAILURE); } } + if (retcode == SQL_NEED_DATA) + { + PTR pParmID; + retcode = SQLParamData(hstmtInsert, &pParmID); + while (retcode == SQL_NEED_DATA) + { + // Find the parameter + int i; + for (i=0; i < noCols; i++) + { + if (colDefs[i].PtrDataObj == pParmID) + { + // We found it. Store the parameter. + retcode = SQLPutData(hstmtInsert, pParmID, colDefs[i].SzDataObj); + if (retcode != SQL_SUCCESS) + { + pDb->DispNextError(); + pDb->DispAllErrors(henv, hdbc, hstmtInsert); + return(DB_FAILURE); + } + break; + } + } + } + } // Record inserted into the datasource successfully return(DB_SUCCESS); @@ -2110,6 +2211,9 @@ void wxDbTable::SetColDefs(UWORD index, const wxString &fieldName, int dataType, SWORD cType, int size, bool keyField, bool upd, bool insAllow, bool derivedCol) { + wxASSERT_MSG( index < noCols, + _T("Specified column index exceeds the maximum number of columns for this table.") ); + if (!colDefs) // May happen if the database connection fails return; @@ -2289,7 +2393,7 @@ ULONG wxDbTable::Count(const wxString &args) } // Execute the SQL statement - if (SQLExecDirect(*hstmtCount, (UCHAR FAR *) sqlStmt.c_str(), SQL_NTS) != SQL_SUCCESS) + if (SQLExecDirect(*hstmtCount, (SQLTCHAR FAR *) sqlStmt.c_str(), SQL_NTS) != SQL_SUCCESS) { pDb->DispAllErrors(henv, hdbc, *hstmtCount); return(0); @@ -2329,8 +2433,8 @@ bool wxDbTable::Refresh(void) hstmt = hstmtInternal; #if wxODBC_BACKWARD_COMPATABILITY // Save the where and order by clauses - char *saveWhere = where; - char *saveOrderBy = orderBy; + wxChar *saveWhere = where; + wxChar *saveOrderBy = orderBy; #else wxString saveWhere = where; wxString saveOrderBy = orderBy; @@ -2394,7 +2498,10 @@ bool wxDbTable::SetColNull(UWORD colNo, bool set) { colDefs[colNo].Null = set; if (set) // Blank out the values in the member variable - ClearMemberVar(colNo,FALSE); // Must call with FALSE, or infinite recursion will happen + { + colDefs[colNo].CbValue = SQL_NULL_DATA; // SF PATCH#766404 + ClearMemberVar(colNo,FALSE); // Must call with FALSE, or infinite recursion will happen + } return(TRUE); } else @@ -2406,18 +2513,21 @@ bool wxDbTable::SetColNull(UWORD colNo, bool set) /********** wxDbTable::SetColNull() **********/ bool wxDbTable::SetColNull(const wxString &colName, bool set) { - int i; - for (i = 0; i < noCols; i++) + int colNo; + for (colNo = 0; colNo < noCols; colNo++) { - if (!wxStricmp(colName, colDefs[i].ColName)) + if (!wxStricmp(colName, colDefs[colNo].ColName)) break; } - if (i < noCols) + if (colNo < noCols) { - colDefs[i].Null = set; + colDefs[colNo].Null = set; if (set) // Blank out the values in the member variable - ClearMemberVar(i,FALSE); // Must call with FALSE, or infinite recursion will happen + { + colDefs[colNo].CbValue = SQL_NULL_DATA; // SF PATCH#766404 + ClearMemberVar(colNo,FALSE); // Must call with FALSE, or infinite recursion will happen + } return(TRUE); } else @@ -2513,7 +2623,7 @@ void wxDbTable::SetRowMode(const rowmode_t rowmode) SetCursor(hstmtDefault); break; default: - assert(0); + wxASSERT(0); } } // wxDbTable::SetRowMode() @@ -2541,10 +2651,10 @@ wxVariant wxDbTable::GetCol(const int colNo) const val = (long)(*(unsigned long *)(colDefs[colNo].PtrDataObj)); break; case SQL_C_TINYINT: - val = (long)(*(char *)(colDefs[colNo].PtrDataObj)); + val = (long)(*(wxChar *)(colDefs[colNo].PtrDataObj)); break; case SQL_C_UTINYINT: - val = (long)(*(unsigned char *)(colDefs[colNo].PtrDataObj)); + val = (long)(*(wxChar *)(colDefs[colNo].PtrDataObj)); break; case SQL_C_USHORT: val = (long)(*(UWORD *)(colDefs[colNo].PtrDataObj)); @@ -2569,14 +2679,6 @@ wxVariant wxDbTable::GetCol(const int colNo) const } // 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.. @@ -2599,7 +2701,7 @@ void wxDbTable::SetCol(const int colNo, const wxVariant val) { case SQL_CHAR: case SQL_VARCHAR: - csstrncpyt((char *)(colDefs[colNo].PtrDataObj), + csstrncpyt((wxChar *)(colDefs[colNo].PtrDataObj), val.GetString().c_str(), colDefs[colNo].SzDataObj-1); break; @@ -2615,10 +2717,10 @@ void wxDbTable::SetCol(const int colNo, const wxVariant val) *(unsigned long *)(colDefs[colNo].PtrDataObj) = val.GetLong(); break; case SQL_C_TINYINT: - *(char *)(colDefs[colNo].PtrDataObj) = val.GetChar(); + *(wxChar *)(colDefs[colNo].PtrDataObj) = val.GetChar(); break; case SQL_C_UTINYINT: - *(unsigned char *)(colDefs[colNo].PtrDataObj) = val.GetChar(); + *(wxChar *)(colDefs[colNo].PtrDataObj) = val.GetChar(); break; case SQL_C_USHORT: *(unsigned short *)(colDefs[colNo].PtrDataObj) = val.GetLong();