///////////////////////////////////////////////////////////////////////////////
-// Name: dbtable.cpp
+// Name: src/common/dbtable.cpp
// Purpose: Implementation of the wxDbTable class.
// Author: Doug Card
// Modified by: George Tasker
// Licence: wxWindows licence
///////////////////////////////////////////////////////////////////////////////
-/*
-// SYNOPSIS START
-// SYNOPSIS STOP
-*/
-
-#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
- #pragma implementation "dbtable.h"
-#endif
-
#include "wx/wxprec.h"
#ifdef __BORLANDC__
#pragma hdrstop
#endif
-#ifdef DBDEBUG_CONSOLE
-#if wxUSE_IOSTREAMH
- #include <iostream.h>
-#else
- #include <iostream>
-#endif
- #include "wx/ioswrap.h"
-#endif
+#if wxUSE_ODBC
#ifndef WX_PRECOMP
- #include "wx/string.h"
#include "wx/object.h"
#include "wx/list.h"
+ #include "wx/string.h"
#include "wx/utils.h"
#include "wx/log.h"
+ #include "wx/crt.h"
#endif
-#include "wx/filefn.h"
-#if wxUSE_ODBC
+#ifdef DBDEBUG_CONSOLE
+ #include "wx/ioswrap.h"
+#endif
+
+#include "wx/filefn.h"
#include <stdio.h>
#include <stdlib.h>
#include "wx/dbtable.h"
-#ifdef __UNIX__
-// The HPUX preprocessor lines below were commented out on 8/20/97
-// because macros.h currently redefines DEBUG and is unneeded.
-// # ifdef HPUX
-// # include <macros.h>
-// # endif
-# ifdef LINUX
-# include <sys/minmax.h>
-# endif
+// FIXME-UTF8: get rid of this after switching to Unicode-only builds:
+#if wxUSE_UNICODE
+ #define WXSQLCAST(s) ((SQLTCHAR FAR *)(wchar_t*)(s).wchar_str())
+#else
+ #define WXSQLCAST(s) ((SQLTCHAR FAR *)(char*)(s).char_str())
#endif
ULONG lastTableID = 0;
#ifdef __WXDEBUG__
+ #include "wx/thread.h"
+
wxList TablesInUse;
+ wxCriticalSection csTablesInUse;
#endif
void csstrncpyt(wxChar *target, const wxChar *source, int n)
{
- while ( (*target++ = *source++) != '\0' && --n )
+ while ( (*target++ = *source++) != '\0' && --n != 0 )
;
*target = '\0';
DerivedCol = false;
CbValue = 0;
Null = false;
+ CbValueCol = 0;
return true;
} // wxDbColDef::Initialize()
} // wxDbTable::wxDbTable()
-/***** DEPRECATED: use wxDbTable::wxDbTable() format above *****/
-#if WXWIN_COMPATIBILITY_2_4
-wxDbTable::wxDbTable(wxDb *pwxDb, const wxString &tblName, const UWORD numColumns,
- const wxChar *qryTblName, bool qryOnly, const wxString &tblPath)
-{
- wxString tempQryTblName;
- tempQryTblName = qryTblName;
- if (!initialize(pwxDb, tblName, numColumns, tempQryTblName, qryOnly, tblPath))
- cleanup();
-} // wxDbTable::wxDbTable()
-#endif // WXWIN_COMPATIBILITY_2_4
-
-
/********** wxDbTable::~wxDbTable() **********/
wxDbTable::~wxDbTable()
{
tableName.Empty();
queryTableName.Empty();
- wxASSERT(tblName.Length());
+ wxASSERT(tblName.length());
wxASSERT(pDb);
if (!pDb)
(pDb->Dbms() == dbmsINTERBASE))
tableName = tableName.Upper();
- if (tblPath.Length())
+ if (tblPath.length())
tablePath = tblPath; // Table Path - used for dBase files
else
tablePath.Empty();
- if (qryTblName.Length()) // Name of the table/view to query
+ if (qryTblName.length()) // Name of the table/view to query
queryTableName = qryTblName;
else
queryTableName = tblName;
wxString s;
tableID = ++lastTableID;
- s.Printf(wxT("wxDbTable constructor (%-20s) tableID:[%6lu] pDb:[%p]"), tblName.c_str(), tableID, pDb);
+ s.Printf(wxT("wxDbTable constructor (%-20s) tableID:[%6lu] pDb:[%p]"),
+ tblName.c_str(), tableID, wx_static_cast(void*, pDb));
#ifdef __WXDEBUG__
wxTablesInUse *tableInUse;
tableInUse->tableName = tblName;
tableInUse->tableID = tableID;
tableInUse->pDb = pDb;
- TablesInUse.Append(tableInUse);
+ {
+ wxCriticalSectionLocker lock(csTablesInUse);
+ TablesInUse.Append(tableInUse);
+ }
#endif
pDb->WriteSqlLog(s);
wxString s;
if (pDb)
{
- s.Printf(wxT("wxDbTable destructor (%-20s) tableID:[%6lu] pDb:[%p]"), tableName.c_str(), tableID, pDb);
+ s.Printf(wxT("wxDbTable destructor (%-20s) tableID:[%6lu] pDb:[%p]"),
+ tableName.c_str(), tableID, wx_static_cast(void*, pDb));
pDb->WriteSqlLog(s);
}
bool found = false;
wxList::compatibility_iterator pNode;
- pNode = TablesInUse.GetFirst();
- while (pNode && !found)
{
- if (((wxTablesInUse *)pNode->GetData())->tableID == tableID)
+ wxCriticalSectionLocker lock(csTablesInUse);
+ pNode = TablesInUse.GetFirst();
+ while (!found && pNode)
{
- found = true;
- delete (wxTablesInUse *)pNode->GetData();
- TablesInUse.Erase(pNode);
+ if (((wxTablesInUse *)pNode->GetData())->tableID == tableID)
+ {
+ found = true;
+ delete (wxTablesInUse *)pNode->GetData();
+ TablesInUse.Erase(pNode);
+ }
+ else
+ pNode = pNode->GetNext();
}
- else
- pNode = pNode->GetNext();
}
if (!found)
{
switch(colDefs[columnIndex].DbDataType)
{
case DB_DATA_TYPE_VARCHAR:
+ case DB_DATA_TYPE_MEMO:
if (colDefs[columnIndex].Null)
colDefs[columnIndex].CbValue = SQL_NULL_DATA;
else
precision = colDefs[i].SzDataObj;
scale = 0;
break;
+ case DB_DATA_TYPE_MEMO:
+ fSqlType = pDb->GetTypeInfMemo().FsqlType;
+ precision = colDefs[i].SzDataObj;
+ scale = 0;
+ break;
case DB_DATA_TYPE_INTEGER:
fSqlType = pDb->GetTypeInfInteger().FsqlType;
precision = pDb->GetTypeInfInteger().Precision;
/********** 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 < m_numCols; i++)
{
- cb = colDefs[i].CbValue;
if (SQLBindCol(cursor, (UWORD)(i+1), colDefs[i].SqlCtype, (UCHAR*) colDefs[i].PtrDataObj,
- colDefs[i].SzDataObj, &cb ) != SQL_SUCCESS)
+ colDefs[i].SzDataObj, &colDefs[i].CbValueCol ) != SQL_SUCCESS)
return (pDb->DispAllErrors(henv, hdbc, cursor));
}
// Completed successfully
return true;
-
} // wxDbTable::bindCols()
if (!pDb->FwdOnlyCursors())
{
// Fetch the NEXT, PREV, FIRST or LAST record, depending on fetchType
- UDWORD cRowsFetched;
+ SQLULEN cRowsFetched;
UWORD rowStatus;
retcode = SQLExtendedFetch(hstmt, fetchType, 0, &cRowsFetched, &rowStatus);
// of each column just read in.
int i;
for (i = 0; i < m_numCols; i++)
- colDefs[i].Null = (colDefs[i].CbValue == SQL_NULL_DATA);
+ colDefs[i].Null = (colDefs[i].CbValueCol == SQL_NULL_DATA);
}
}
else
// of each column just read in.
int i;
for (i = 0; i < m_numCols; i++)
- colDefs[i].Null = (colDefs[i].CbValue == SQL_NULL_DATA);
+ colDefs[i].Null = (colDefs[i].CbValueCol == SQL_NULL_DATA);
}
}
RETCODE retcode;
// Execute the DELETE statement
- retcode = SQLExecDirect(hstmtDelete, (SQLTCHAR FAR *) pSqlStmt.c_str(), SQL_NTS);
+ retcode = SQLExecDirect(hstmtDelete, WXSQLCAST(pSqlStmt), SQL_NTS);
if (retcode == SQL_SUCCESS ||
retcode == SQL_NO_DATA_FOUND ||
RETCODE retcode;
// Execute the UPDATE statement
- retcode = SQLExecDirect(hstmtUpdate, (SQLTCHAR FAR *) pSqlStmt.c_str(), SQL_NTS);
+ retcode = SQLExecDirect(hstmtUpdate, WXSQLCAST(pSqlStmt), SQL_NTS);
if (retcode == SQL_SUCCESS ||
retcode == SQL_NO_DATA_FOUND ||
// Execute the SQL SELECT statement
int retcode;
- retcode = SQLExecDirect(hstmt, (SQLTCHAR FAR *) (queryType == DB_SELECT_STATEMENT ? pSqlStmt.c_str() : sqlStmt.c_str()), SQL_NTS);
+ retcode = SQLExecDirect(hstmt, (queryType == DB_SELECT_STATEMENT ? WXSQLCAST(pSqlStmt) : WXSQLCAST(sqlStmt)), SQL_NTS);
if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO)
return(pDb->DispAllErrors(henv, hdbc, hstmt));
// Prepare the insert statement for execution
if (insertableCount)
{
- if (SQLPrepare(hstmtInsert, (SQLTCHAR FAR *) sqlStmt.c_str(), SQL_NTS) != SQL_SUCCESS)
+ if (SQLPrepare(hstmtInsert, WXSQLCAST(sqlStmt), SQL_NTS) != SQL_SUCCESS)
return(pDb->DispAllErrors(henv, hdbc, hstmtInsert));
}
else
// Handle the case of DeleteWhere() and the where clause is blank. It should
// delete all records from the database in this case.
- if (typeOfDel == DB_DEL_WHERE && (pWhereClause.Length() == 0))
+ if (typeOfDel == DB_DEL_WHERE && (pWhereClause.length() == 0))
{
pSqlStmt.Printf(wxT("DELETE FROM %s"),
pDb->SQLTableName(tableName.c_str()).c_str());
// e.g. DELETE FROM PARTS WHERE ROWID = '111.222.333'
if (CanUpdateByROWID())
{
- SDWORD cb;
+ SQLLEN cb;
wxChar rowid[wxDB_ROWID_LEN+1];
// Get the ROWID value. If not successful retreiving the ROWID,
if (typeOfSelect == DB_SELECT_WHERE && from && wxStrlen(from))
appendFromClause = true;
#else
- if (typeOfSelect == DB_SELECT_WHERE && from.Length())
+ if (typeOfSelect == DB_SELECT_WHERE && from.length())
appendFromClause = true;
#endif
#if wxODBC_BACKWARD_COMPATABILITY
if (where && wxStrlen(where)) // May not want a where clause!!!
#else
- if (where.Length()) // May not want a where clause!!!
+ if (where.length()) // May not want a where clause!!!
#endif
{
pSqlStmt += wxT(" WHERE ");
break;
case DB_SELECT_KEYFIELDS:
BuildWhereClause(whereClause, DB_WHERE_KEYFIELDS);
- if (whereClause.Length())
+ if (whereClause.length())
{
pSqlStmt += wxT(" WHERE ");
pSqlStmt += whereClause;
break;
case DB_SELECT_MATCHING:
BuildWhereClause(whereClause, DB_WHERE_MATCHING);
- if (whereClause.Length())
+ if (whereClause.length())
{
pSqlStmt += wxT(" WHERE ");
pSqlStmt += whereClause;
#if wxODBC_BACKWARD_COMPATABILITY
if (orderBy && wxStrlen(orderBy))
#else
- if (orderBy.Length())
+ if (orderBy.length())
#endif
{
pSqlStmt += wxT(" ORDER BY ");
// e.g. UPDATE PARTS SET Col1 = ?, Col2 = ? WHERE ROWID = '111.222.333'
if (CanUpdateByROWID())
{
- SDWORD cb;
+ SQLLEN cb;
wxChar rowid[wxDB_ROWID_LEN+1];
// Get the ROWID value. If not successful retreiving the ROWID,
// Concatenate where phrase for the column
wxString tStr = colDefs[colNumber].ColName;
- if (qualTableName.Length() && tStr.Find(wxT('.')) == wxNOT_FOUND)
+ if (qualTableName.length() && tStr.Find(wxT('.')) == wxNOT_FOUND)
{
pWhereClause += pDb->SQLTableName(qualTableName);
pWhereClause += wxT(".");
case SQL_C_WCHAR:
#endif
//case SQL_C_WXCHAR: SQL_C_WXCHAR is covered by either SQL_C_CHAR or SQL_C_WCHAR
- colValue.Printf(wxT("'%s'"), (UCHAR FAR *) colDefs[colNumber].PtrDataObj);
+ colValue.Printf(wxT("'%s'"), GetDb()->EscapeSqlChars((wxChar *)colDefs[colNumber].PtrDataObj).c_str());
break;
case SQL_C_SHORT:
case SQL_C_SSHORT:
case DB_DATA_TYPE_VARCHAR:
cout << pDb->GetTypeInfVarchar().TypeName << wxT("(") << (int)(colDefs[i].SzDataObj / sizeof(wxChar)) << wxT(")");
break;
+ case DB_DATA_TYPE_MEMO:
+ cout << pDb->GetTypeInfMemo().TypeName;
+ break;
case DB_DATA_TYPE_INTEGER:
cout << pDb->GetTypeInfInteger().TypeName;
break;
case DB_DATA_TYPE_VARCHAR:
sqlStmt += pDb->GetTypeInfVarchar().TypeName;
break;
+ case DB_DATA_TYPE_MEMO:
+ sqlStmt += pDb->GetTypeInfMemo().TypeName;
+ break;
case DB_DATA_TYPE_INTEGER:
sqlStmt += pDb->GetTypeInfInteger().TypeName;
break;
// DB2 is limited to 18 characters for index names
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."));
+ wxASSERT_MSG(!tableName.empty() && tableName.length() <= 13, wxT("DB2 table/index names must be no longer than 13 characters in length.\n\nTruncating table name to 13 characters."));
sqlStmt += pDb->SQLTableName(tableName.substr(0, 13).c_str());
// sqlStmt += tableName.substr(0, 13);
}
#endif
// Execute the CREATE TABLE statement
- RETCODE retcode = SQLExecDirect(hstmt, (SQLTCHAR FAR *) sqlStmt.c_str(), SQL_NTS);
+ RETCODE retcode = SQLExecDirect(hstmt, WXSQLCAST(sqlStmt), SQL_NTS);
if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO)
{
pDb->DispAllErrors(henv, hdbc, hstmt);
cout << endl << sqlStmt.c_str() << endl;
#endif
- RETCODE retcode = SQLExecDirect(hstmt, (SQLTCHAR FAR *) sqlStmt.c_str(), SQL_NTS);
+ RETCODE retcode = SQLExecDirect(hstmt, WXSQLCAST(sqlStmt), SQL_NTS);
if (retcode != SQL_SUCCESS)
{
// Check for "Base table not found" error and ignore
#endif
// Execute the CREATE INDEX statement
- RETCODE retcode = SQLExecDirect(hstmt, (SQLTCHAR FAR *) sqlStmt.c_str(), SQL_NTS);
+ RETCODE retcode = SQLExecDirect(hstmt, WXSQLCAST(sqlStmt), SQL_NTS);
if (retcode != SQL_SUCCESS)
{
pDb->DispAllErrors(henv, hdbc, hstmt);
#ifdef DBDEBUG_CONSOLE
cout << endl << sqlStmt.c_str() << endl;
#endif
- RETCODE retcode = SQLExecDirect(hstmt, (SQLTCHAR FAR *) sqlStmt.c_str(), SQL_NTS);
+ RETCODE retcode = SQLExecDirect(hstmt, WXSQLCAST(sqlStmt), SQL_NTS);
if (retcode != SQL_SUCCESS)
{
// Check for "Index not found" error and ignore
pDt->second = 0;
pDt->fraction = 0;
break;
+ case SQL_C_DATE:
+ DATE_STRUCT *pDtd;
+ pDtd = (DATE_STRUCT *) colDefs[colNumber].PtrDataObj;
+ pDtd->year = 0;
+ pDtd->month = 0;
+ pDtd->day = 0;
+ break;
+ case SQL_C_TIME:
+ TIME_STRUCT *pDtt;
+ pDtt = (TIME_STRUCT *) colDefs[colNumber].PtrDataObj;
+ pDtt->hour = 0;
+ pDtt->minute = 0;
+ pDtt->second = 0;
+ break;
}
if (setToNull)
if (!colDefs) // May happen if the database connection fails
return false;
- if (fieldName.Length() > (unsigned int) DB_MAX_COLUMN_NAME_LEN)
+ if (fieldName.length() > (unsigned int) DB_MAX_COLUMN_NAME_LEN)
{
wxStrncpy(colDefs[index].ColName, fieldName, DB_MAX_COLUMN_NAME_LEN);
colDefs[index].ColName[DB_MAX_COLUMN_NAME_LEN] = 0; // Prevent buffer overrun
pColDataPtrs[index].SzDataObj = pColInfs[index].bufferSize+(1*sizeof(wxChar));
pColDataPtrs[index].SqlCtype = SQL_C_WXCHAR;
break;
+ case DB_DATA_TYPE_MEMO:
+ pColDataPtrs[index].PtrDataObj = new wxChar[pColInfs[index].bufferSize+(1*sizeof(wxChar))];
+ pColDataPtrs[index].SzDataObj = pColInfs[index].bufferSize+(1*sizeof(wxChar));
+ pColDataPtrs[index].SqlCtype = SQL_C_WXCHAR;
+ break;
case DB_DATA_TYPE_INTEGER:
// Can be long or short
if (pColInfs[index].bufferSize == sizeof(long))
{
ULONG count;
wxString sqlStmt;
- SDWORD cb;
+ SQLLEN cb;
// Build a "SELECT COUNT(*) FROM queryTableName [WHERE whereClause]" SQL Statement
sqlStmt = wxT("SELECT COUNT(");
#if wxODBC_BACKWARD_COMPATABILITY
if (from && wxStrlen(from))
#else
- if (from.Length())
+ if (from.length())
#endif
sqlStmt += from;
#if wxODBC_BACKWARD_COMPATABILITY
if (where && wxStrlen(where))
#else
- if (where.Length())
+ if (where.length())
#endif
{
sqlStmt += wxT(" WHERE ");
}
// Execute the SQL statement
- if (SQLExecDirect(*hstmtCount, (SQLTCHAR FAR *) sqlStmt.c_str(), SQL_NTS) != SQL_SUCCESS)
+ if (SQLExecDirect(*hstmtCount, WXSQLCAST(sqlStmt), SQL_NTS) != SQL_SUCCESS)
{
pDb->DispAllErrors(henv, hdbc, *hstmtCount);
return(0);
if (CanUpdateByROWID())
{
- SDWORD cb;
+ SQLLEN cb;
wxChar rowid[wxDB_ROWID_LEN+1];
// Get the ROWID value. If not successful retreiving the ROWID,
#endif // wxUSE_ODBC
-