///////////////////////////////////////////////////////////////////////////////
-// 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
+#if wxUSE_ODBC
+
+#ifndef WX_PRECOMP
+ #include "wx/object.h"
+ #include "wx/list.h"
+ #include "wx/string.h"
+ #include "wx/utils.h"
+ #include "wx/log.h"
+#endif
+
#ifdef DBDEBUG_CONSOLE
#if wxUSE_IOSTREAMH
#include <iostream.h>
#include "wx/ioswrap.h"
#endif
-#ifndef WX_PRECOMP
- #include "wx/string.h"
- #include "wx/object.h"
- #include "wx/list.h"
- #include "wx/utils.h"
- #include "wx/log.h"
-#endif
#include "wx/filefn.h"
-#if wxUSE_ODBC
-
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void csstrncpyt(wxChar *target, const wxChar *source, int n)
{
- while ( (*target++ = *source++) != '\0' && --n )
+ while ( (*target++ = *source++) != '\0' && --n != 0 )
;
*target = '\0';
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;
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);
}
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].CbValue ) != 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);
int i;
wxString sqlStmt;
wxString s;
-// int NumKeyCols=0;
// Calculate the maximum size of the concatenated
// keys for use with wxDbGrid
{
if (colDefs[i].KeyField)
{
-// NumKeyCols++;
m_keysize += colDefs[i].SzDataObj;
}
}
s.Empty();
+
+ bool exists = true;
+ if (checkTableExists)
+ {
+ if (pDb->Dbms() == dbmsPOSTGRES)
+ exists = pDb->TableExists(tableName, NULL, tablePath);
+ else
+ exists = pDb->TableExists(tableName, pDb->GetUsername(), tablePath);
+ }
+
// Verify that the table exists in the database
- if (checkTableExists && !pDb->TableExists(tableName, pDb->GetUsername(), tablePath))
+ if (!exists)
{
s = wxT("Table/view does not exist in the database");
if ( *(pDb->dbInf.accessibleTables) == wxT('Y'))
else if (checkPrivileges)
{
// Verify the user has rights to access the table.
- // Shortcut boolean evaluation to optimize out call to
- // TablePrivileges
- //
- // Unfortunately this optimization doesn't seem to be
- // reliable!
- if (// *(pDb->dbInf.accessibleTables) == 'N' &&
- !pDb->TablePrivileges(tableName, wxT("SELECT"), pDb->GetUsername(), pDb->GetUsername(), tablePath))
+ bool hasPrivs wxDUMMY_INITIALIZE(true);
+
+ if (pDb->Dbms() == dbmsPOSTGRES)
+ hasPrivs = pDb->TablePrivileges(tableName, wxT("SELECT"), pDb->GetUsername(), NULL, tablePath);
+ else
+ hasPrivs = pDb->TablePrivileges(tableName, wxT("SELECT"), pDb->GetUsername(), pDb->GetUsername(), tablePath);
+
+ if (!hasPrivs)
s = wxT("Connecting user does not have sufficient privileges to access this table.\n");
}
- if (!s.IsEmpty())
+ if (!s.empty())
{
wxString p;
- if (!tablePath.IsEmpty())
+ if (!tablePath.empty())
p.Printf(wxT("Error opening '%s/%s'.\n"),tablePath.c_str(),tableName.c_str());
else
p.Printf(wxT("Error opening '%s'.\n"), tableName.c_str());
if (needComma)
sqlStmt += wxT(",");
sqlStmt += pDb->SQLColumnName(colDefs[i].ColName);
-// sqlStmt += colDefs[i].ColName;
needComma = true;
}
needComma = false;
// 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
{
pSqlStmt += wxT(",");
pSqlStmt += pDb->SQLTableName(queryTableName);
-// pSqlStmt += queryTableName;
pSqlStmt += wxT(".ROWID");
}
else
#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 ");
/********** wxDbTable::BuildUpdateStmt() **********/
-void wxDbTable::BuildUpdateStmt(wxString &pSqlStmt, int typeOfUpd, const wxString &pWhereClause)
+void wxDbTable::BuildUpdateStmt(wxString &pSqlStmt, int typeOfUpdate, const wxString &pWhereClause)
{
wxASSERT(!queryOnly);
if (queryOnly)
// Append the WHERE clause to the SQL UPDATE statement
pSqlStmt += wxT(" WHERE ");
- switch(typeOfUpd)
+ switch(typeOfUpdate)
{
case DB_UPD_KEYFIELDS:
// If the datasource supports the ROWID column, build
// 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,
/***** DEPRECATED: use wxDbTable::BuildUpdateStmt(wxString &....) form *****/
-void wxDbTable::BuildUpdateStmt(wxChar *pSqlStmt, int typeOfUpd, const wxString &pWhereClause)
+void wxDbTable::BuildUpdateStmt(wxChar *pSqlStmt, int typeOfUpdate, const wxString &pWhereClause)
{
wxString tempSqlStmt;
- BuildUpdateStmt(tempSqlStmt, typeOfUpd, pWhereClause);
+ BuildUpdateStmt(tempSqlStmt, typeOfUpdate, pWhereClause);
wxStrcpy(pSqlStmt, tempSqlStmt);
} // BuildUpdateStmt()
// 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(".");
switch(colDefs[colNumber].SqlCtype)
{
case SQL_C_CHAR:
-#ifndef __UNIX__
+#ifdef SQL_C_WCHAR
case SQL_C_WCHAR:
-#endif
+#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;
/********** wxDbTable::CreateIndex() **********/
-bool wxDbTable::CreateIndex(const wxString &idxName, bool unique, UWORD noIdxCols,
- wxDbIdxDef *pIdxDefs, bool attemptDrop)
+bool wxDbTable::CreateIndex(const wxString &indexName, bool unique, UWORD numIndexColumns,
+ wxDbIdxDef *pIndexDefs, bool attemptDrop)
{
wxString sqlStmt;
// Drop the index first
- if (attemptDrop && !DropIndex(idxName))
+ if (attemptDrop && !DropIndex(indexName))
return false;
// MySQL (and possibly Sybase ASE?? - gt) require that any columns which are used as portions
wxString sqlStmt;
int i;
bool ok = true;
- for (i = 0; i < noIdxCols && ok; i++)
+ for (i = 0; i < numIndexColumns && ok; i++)
{
int j = 0;
bool found = false;
// this information
while (!found && (j < this->m_numCols))
{
- if (wxStrcmp(colDefs[j].ColName,pIdxDefs[i].ColName) == 0)
+ if (wxStrcmp(colDefs[j].ColName,pIndexDefs[i].ColName) == 0)
found = true;
if (!found)
j++;
if (found)
{
- ok = pDb->ModifyColumn(tableName, pIdxDefs[i].ColName,
+ ok = pDb->ModifyColumn(tableName, pIndexDefs[i].ColName,
colDefs[j].DbDataType, (int)(colDefs[j].SzDataObj / sizeof(wxChar)),
wxT("NOT NULL"));
sqlStmt += wxT("UNIQUE ");
sqlStmt += wxT("INDEX ");
- sqlStmt += pDb->SQLTableName(idxName);
+ sqlStmt += pDb->SQLTableName(indexName);
sqlStmt += wxT(" ON ");
sqlStmt += pDb->SQLTableName(tableName);
// Append list of columns making up index
int i;
- for (i = 0; i < noIdxCols; i++)
+ for (i = 0; i < numIndexColumns; i++)
{
- sqlStmt += pDb->SQLColumnName(pIdxDefs[i].ColName);
-// sqlStmt += pIdxDefs[i].ColName;
+ sqlStmt += pDb->SQLColumnName(pIndexDefs[i].ColName);
+// sqlStmt += pIndexDefs[i].ColName;
// MySQL requires a key length on VARCHAR keys
if ( pDb->Dbms() == dbmsMY_SQL )
int j;
for ( j = 0; j < m_numCols; ++j )
{
- if ( wxStrcmp( pIdxDefs[i].ColName, colDefs[j].ColName ) == 0 )
+ if ( wxStrcmp( pIndexDefs[i].ColName, colDefs[j].ColName ) == 0 )
{
break;
}
!(pDb->Dbms() == dbmsFIREBIRD) &&
!(pDb->Dbms() == dbmsPOSTGRES))
{
- if (pIdxDefs[i].Ascending)
+ if (pIndexDefs[i].Ascending)
sqlStmt += wxT(" ASC");
else
sqlStmt += wxT(" DESC");
}
else
- wxASSERT_MSG(pIdxDefs[i].Ascending, _T("Datasource does not support DESCending index columns"));
+ wxASSERT_MSG(pIndexDefs[i].Ascending, _T("Datasource does not support DESCending index columns"));
- if ((i + 1) < noIdxCols)
+ if ((i + 1) < numIndexColumns)
sqlStmt += wxT(",");
}
/********** wxDbTable::DropIndex() **********/
-bool wxDbTable::DropIndex(const wxString &idxName)
+bool wxDbTable::DropIndex(const wxString &indexName)
{
// NOTE: This function returns true if the Index does not exist, but
// only for identified databases. Code will need to be added
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"),
- pDb->SQLTableName(idxName.c_str()).c_str(),
+ pDb->SQLTableName(indexName.c_str()).c_str(),
pDb->SQLTableName(tableName.c_str()).c_str());
else if ((pDb->Dbms() == dbmsMS_SQL_SERVER) ||
(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());
+ pDb->SQLTableName(indexName.c_str()).c_str());
else
sqlStmt.Printf(wxT("DROP INDEX %s"),
- pDb->SQLTableName(idxName.c_str()).c_str());
+ pDb->SQLTableName(indexName.c_str()).c_str());
pDb->WriteSqlLog(sqlStmt);
(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() == dbmsMAXDB && !wxStrcmp(pDb->sqlState,wxT("S1000"))) ||
(pDb->Dbms() == dbmsFIREBIRD && !wxStrcmp(pDb->sqlState,wxT("HY000"))) ||
(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
switch(colDefs[colNumber].SqlCtype)
{
case SQL_C_CHAR:
-#ifndef __UNIX__
+#ifdef SQL_C_WCHAR
case SQL_C_WCHAR:
#endif
//case SQL_C_WXCHAR: SQL_C_WXCHAR is covered by either SQL_C_CHAR or SQL_C_WCHAR
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)
/********** wxDbTable::SetColDefs() **********/
bool wxDbTable::SetColDefs(UWORD index, const wxString &fieldName, int dataType, void *pData,
SWORD cType, int size, bool keyField, bool updateable,
- bool insAllow, bool derivedCol)
+ bool insertAllowed, bool derivedColumn)
{
wxString tmpStr;
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
colDefs[index].SqlCtype = cType;
colDefs[index].SzDataObj = size; //TODO: glt ??? * sizeof(wxChar) ???
colDefs[index].KeyField = keyField;
- colDefs[index].DerivedCol = derivedCol;
+ colDefs[index].DerivedCol = derivedColumn;
// Derived columns by definition would NOT be "Insertable" or "Updateable"
- if (derivedCol)
+ if (derivedColumn)
{
colDefs[index].Updateable = false;
colDefs[index].InsertAllowed = false;
else
{
colDefs[index].Updateable = updateable;
- colDefs[index].InsertAllowed = insAllow;
+ colDefs[index].InsertAllowed = insertAllowed;
}
colDefs[index].Null = false;
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 ");
if (CanUpdateByROWID())
{
- SDWORD cb;
+ SQLLEN cb;
wxChar rowid[wxDB_ROWID_LEN+1];
// Get the ROWID value. If not successful retreiving the ROWID,
{
switch (colDefs[colNumber].SqlCtype)
{
+#if wxUSE_UNICODE
+ #if defined(SQL_WCHAR)
+ case SQL_WCHAR:
+ #endif
+ #if defined(SQL_WVARCHAR)
+ case SQL_WVARCHAR:
+ #endif
+#endif
case SQL_CHAR:
case SQL_VARCHAR:
val = (wxChar *)(colDefs[colNumber].PtrDataObj);
switch (colDefs[colNumber].SqlCtype)
{
+#if wxUSE_UNICODE
+ #if defined(SQL_WCHAR)
+ case SQL_WCHAR:
+ #endif
+ #if defined(SQL_WVARCHAR)
+ case SQL_WVARCHAR:
+ #endif
+#endif
case SQL_CHAR:
case SQL_VARCHAR:
csstrncpyt((wxChar *)(colDefs[colNumber].PtrDataObj),
#endif // wxUSE_ODBC
-